﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Data;
using System.Data.Common;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using System.Reflection;

using Noris.Schedule.Support;
using Noris.Schedule.Support.Data;
using Noris.Schedule.Support.DataFace;

namespace Noris.Schedule.Support.Sql
{
	#region class Db_Layer : ON-THE-FLY NAČÍTÁNÍ DAT Z SQL ZDROJE PŘÍMO DO STRUKTUROVANÉHO ZÁZNAMU / LISTU / DICTIONARY, UKLÁDÁNÍ DAT
	/// <summary>
	/// Třída, která obsahuje statické metody pro načítání dat z SQL zdroje do stukturovaných záznamů.
	/// Na vstupu je SQL SELECT příkaz, který načítá potřebná data.
	/// Dalším vstupem je datový typ struktury, jejíž záznamy se vytvářejí (typový parametr, generikum).
	/// Výstupem je typicky seznam záznamů (List) dané generické třídy, nebo jednotlivý záznam, anebo Dictionary.
	/// Generický typ musí splňovat jednoduchou zásadu, pokud chceme načítat data ze selectu do objektu: 
	/// třída musí obsahovat instanční fields, odpovídající columnům v přicházejících datech.
	/// Jméno fields musí začínat podtržítkem (to je navíc, proti jménu columnu v selectu!), a musí být uvedeno malými písmeny.
	/// Datové typy (SQL =» FIELD) mají být konvertibilní. 
	/// Pozor na použití Non-SQL typů ve struktuře: pokud vstupní data budou obsahovat NULL, dojde k chybě při načítání.
	/// Na vstupu může být NULL i ve sloupcích z LEFT OUTER JOIN tabulek.
	/// Buď je třeba používat Sql datové typy, anebo v SELECTU zamezit výskytu NULL (např. isnull(column, 0)).
	/// </summary>
	public class Db_Layer 
	{
		#region Čtení dat - GetList
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <returns>Seznam záznamů</returns>
		public static List<T> GetList<T>(string sqlCommand) where T : new()
		{
			return _GetList<T>(sqlCommand, null, 0, -1, null);
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <returns>Seznam záznamů</returns>
		public static List<T> GetList<T>(string sqlCommand, int timeOut) where T : new()
		{
			return _GetList<T>(sqlCommand, null, timeOut, -1, null);
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
		/// <returns>Seznam záznamů</returns>
		public static List<T> GetList<T>(string sqlCommand, int timeOut, int maxRecCount) where T : new()
		{
			return _GetList<T>(sqlCommand, null, timeOut, maxRecCount, null);
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <returns>Seznam záznamů</returns>
		public static List<T> GetList<T>(string sqlCommand, SqlParameterCollection parameters) where T : new()
		{
			return _GetList<T>(sqlCommand, parameters, 0, -1, null);
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <returns>Seznam záznamů</returns>
		public static List<T> GetList<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut) where T : new()
		{
			return _GetList<T>(sqlCommand, parameters, timeOut, -1, null);
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
		/// <returns>Seznam záznamů</returns>
		public static List<T> GetList<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, int maxRecCount) where T : new()
		{
			return _GetList<T>(sqlCommand, parameters, timeOut, maxRecCount, null);
		}
        /// <summary>
        /// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
        /// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
        /// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static List<T> GetList<T>(string sqlCommand, DataConnectType connectType) where T : new()
        {
            return _GetList<T>(sqlCommand, null, 0, -1, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
        /// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
        /// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static List<T> GetList<T>(string sqlCommand, int timeOut, DataConnectType connectType) where T : new()
        {
            return _GetList<T>(sqlCommand, null, timeOut, -1, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
        /// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
        /// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static List<T> GetList<T>(string sqlCommand, int timeOut, int maxRecCount, DataConnectType connectType) where T : new()
        {
            return _GetList<T>(sqlCommand, null, timeOut, maxRecCount, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
        /// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
        /// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static List<T> GetList<T>(string sqlCommand, SqlParameterCollection parameters, DataConnectType connectType) where T : new()
        {
            return _GetList<T>(sqlCommand, parameters, 0, -1, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
        /// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
        /// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static List<T> GetList<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnectType connectType) where T : new()
        {
            return _GetList<T>(sqlCommand, parameters, timeOut, -1, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
        /// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
        /// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static List<T> GetList<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, int maxRecCount, DataConnectType connectType) where T : new()
        {
            return _GetList<T>(sqlCommand, parameters, timeOut, maxRecCount, _GetConnector(connectType));
        }
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static List<T> GetList<T>(string sqlCommand, DataConnector connector) where T : new()
		{
			return _GetList<T>(sqlCommand, null, 0, -1, connector);
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static List<T> GetList<T>(string sqlCommand, int timeOut, DataConnector connector) where T : new()
		{
			return _GetList<T>(sqlCommand, null, timeOut, -1, connector);
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static List<T> GetList<T>(string sqlCommand, int timeOut, int maxRecCount, DataConnector connector) where T : new()
		{
			return _GetList<T>(sqlCommand, null, timeOut, maxRecCount, connector);
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static List<T> GetList<T>(string sqlCommand, SqlParameterCollection parameters, DataConnector connector) where T : new()
		{
			return _GetList<T>(sqlCommand, parameters, 0, -1, connector);
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static List<T> GetList<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnector connector) where T : new()
		{
			return _GetList<T>(sqlCommand, parameters, timeOut, -1, connector);
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// Generická třída může v této metodě být buď struktura, anebo primitivní datový typ kromě stringu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static List<T> GetList<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, int maxRecCount, DataConnector connector) where T : new()
		{
			return _GetList<T>(sqlCommand, parameters, timeOut, maxRecCount, connector);
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		private static List<T> _GetList<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, int maxRecCount, DataConnector connector) where T : new()
		{
			List<T> result = null;
			if (IsPrimitiveType(typeof(T)))
				result = _GetListPrimitive<T>(sqlCommand, parameters, timeOut, maxRecCount, connector);
			else
				result = _GetListStructure<T>(sqlCommand, parameters, timeOut, maxRecCount, connector);
			return result;
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		private static List<T> _GetListPrimitive<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, int maxRecCount, DataConnector connector) where T : new()
		{
			// Pokud není zadán explicitní konektor na data, použije se výchozí.
			if (connector == null) connector = DataConnect.CurrentConnect;

            List<T> result = new List<T>();
            using (var scope = Steward.TraceScopeBegin("Db_Layer", "GetListPrimitive", "SQL", connector.ConnectType.ToString(), sqlCommand))
            {
                int recCount = 0;
                try
                {
                    using (DataCommand command = connector.CreateCommand(sqlCommand, parameters, timeOut))
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            recCount++;
                            if (maxRecCount >= 0 && recCount > maxRecCount) break;

                            result.Add((T)reader.GetValue(0));
                        }
                        reader.Close();
                    }
                }
                catch (SqlException exc)
                {
                    throw new SqdException(exc.Message + Environment.NewLine + sqlCommand, exc);
                }
                scope.User = new string[] { result.Count.ToString() };
            }
			return result;
		}
		/// <summary>
		/// Načte seznam záznamů. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		private static List<T> _GetListStructure<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, int maxRecCount, DataConnector connector) where T : new()
		{
			// Pokud není zadán explicitní konektor na data, použije se výchozí.
			if (connector == null) connector = DataConnect.CurrentConnect;

			List<T> result = new List<T>();
            using (var scope = Steward.TraceScopeBegin("Db_Layer", "GetListStructure", "SQL", connector.ConnectType.ToString(), sqlCommand))
            {
                FieldMapperLoad map = null;       // Mapu vytvořím až po otevření readeru
                int recCount = 0;
                try
                {
                    using (DataCommand command = connector.CreateCommand(sqlCommand, parameters, timeOut))
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            if (map == null)
                                map = FieldMapperLoad.GetMap(typeof(T), reader);

                            recCount++;
                            if (maxRecCount >= 0 && recCount > maxRecCount) break;

                            T record = _CreateRecord<T>(reader, map);
                            result.Add(record);
                        }
                        reader.Close();
                    }
                }
                catch (SqlException exc)
                {
                    throw new SqdException(exc.Message + Environment.NewLine + sqlCommand, exc);
                }
                scope.User = new string[] { result.Count.ToString() };
            }
			return result;
		}
		#endregion
		#region Čtení dat - GetListString
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <returns></returns>
		public static List<string> GetListString(string sqlCommand)
		{
			return _GetListString(sqlCommand, null, 0, -1, null);
		}
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <returns></returns>
		public static List<string> GetListString(string sqlCommand, int timeOut)
		{
			return _GetListString(sqlCommand, null, timeOut, -1, null);
		}
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
		/// <returns></returns>
		public static List<string> GetListString(string sqlCommand, int timeOut, int maxRecCount)
		{
			return _GetListString(sqlCommand, null, timeOut, maxRecCount, null);
		}
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <returns></returns>
		public static List<string> GetListString(string sqlCommand, SqlParameterCollection parameters)
		{
			return _GetListString(sqlCommand, parameters, 0, -1, null);
		}
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <returns></returns>
		public static List<string> GetListString(string sqlCommand, SqlParameterCollection parameters, int timeOut)
		{
			return _GetListString(sqlCommand, parameters, timeOut, -1, null);
		}
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
		/// <returns></returns>
		public static List<string> GetListString(string sqlCommand, SqlParameterCollection parameters, int timeOut, int maxRecCount)
		{
			return _GetListString(sqlCommand, parameters, timeOut, maxRecCount, null);
		}
        /// <summary>
        /// Načte seznam stringů.
        /// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
        /// Proto má tuto svojí metodu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static List<string> GetListString(string sqlCommand, DataConnectType connectType)
        {
            return _GetListString(sqlCommand, null, 0, -1, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte seznam stringů.
        /// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
        /// Proto má tuto svojí metodu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static List<string> GetListString(string sqlCommand, int timeOut, DataConnectType connectType)
        {
            return _GetListString(sqlCommand, null, timeOut, -1, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte seznam stringů.
        /// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
        /// Proto má tuto svojí metodu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static List<string> GetListString(string sqlCommand, int timeOut, int maxRecCount, DataConnectType connectType)
        {
            return _GetListString(sqlCommand, null, timeOut, maxRecCount, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte seznam stringů.
        /// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
        /// Proto má tuto svojí metodu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static List<string> GetListString(string sqlCommand, SqlParameterCollection parameters, DataConnectType connectType)
        {
            return _GetListString(sqlCommand, parameters, 0, -1, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte seznam stringů.
        /// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
        /// Proto má tuto svojí metodu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static List<string> GetListString(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnectType connectType)
        {
            return _GetListString(sqlCommand, parameters, timeOut, -1, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte seznam stringů.
        /// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
        /// Proto má tuto svojí metodu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static List<string> GetListString(string sqlCommand, SqlParameterCollection parameters, int timeOut, int maxRecCount, DataConnectType connectType)
        {
            return _GetListString(sqlCommand, parameters, timeOut, maxRecCount, _GetConnector(connectType));
        }
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		public static List<string> GetListString(string sqlCommand, DataConnector connector)
		{
			return _GetListString(sqlCommand, null, 0, -1, connector);
		}
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		public static List<string> GetListString(string sqlCommand, int timeOut, DataConnector connector)
		{
			return _GetListString(sqlCommand, null, timeOut, -1, connector);
		}
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		public static List<string> GetListString(string sqlCommand, int timeOut, int maxRecCount, DataConnector connector)
		{
			return _GetListString(sqlCommand, null, timeOut, maxRecCount, connector);
		}
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		public static List<string> GetListString(string sqlCommand, SqlParameterCollection parameters, DataConnector connector)
		{
			return _GetListString(sqlCommand, parameters, 0, -1, connector);
		}
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		public static List<string> GetListString(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnector connector)
		{
			return _GetListString(sqlCommand, parameters, timeOut, -1, connector);
		}
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		public static List<string> GetListString(string sqlCommand, SqlParameterCollection parameters, int timeOut, int maxRecCount, DataConnector connector)
		{
			return _GetListString(sqlCommand, parameters, timeOut, maxRecCount, connector);
		}
		/// <summary>
		/// Načte seznam stringů.
		/// String je jediný primitiv, který nemůže projít metodou GetList jako generikum, protože string nemá bezparametrický konstruktor.
		/// Proto má tuto svojí metodu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="maxRecCount">Počet záznamů k načtení - ačkoliv rozumnější je specifikovat TOP nn v SQL select příkazu</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		private static List<string> _GetListString(string sqlCommand, SqlParameterCollection parameters, int timeOut, int maxRecCount, DataConnector connector)
		{
			// Pokud není zadán explicitní konektor na data, použije se výchozí.
			if (connector == null) connector = DataConnect.CurrentConnect;

			List<string> result = new List<string>();
			int recCount = 0;
			try
			{
                using (var scope = Steward.TraceScopeBegin("Db_Layer", "GetListString", "SQL", connector.ConnectType.ToString(), sqlCommand))
                using (DataCommand command = connector.CreateCommand(sqlCommand, parameters, timeOut))
                using (SqlDataReader reader = command.ExecuteReader())
				{
					while (reader.Read())
					{
						recCount++;
						if (maxRecCount >= 0 && recCount > maxRecCount) break;

						result.Add(reader.GetString(0));
					}
					reader.Close();
				}
			}
			catch (SqlException exc)
			{
				throw new SqdException(exc.Message + Environment.NewLine + sqlCommand, exc);
			}
			return result;
		}
		#endregion
		#region Čtení dat - GetDictionary
		/// <summary>
		/// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
		/// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
		/// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
		/// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
		/// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <returns>Seznam záznamů</returns>
		public static Dictionary<int, T> GetDictionary<T>(string sqlCommand) where T : new()
		{
			return _GetDictionary<T>(sqlCommand, null, 0, null);
		}
		/// <summary>
		/// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
		/// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
		/// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
		/// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
		/// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <returns>Seznam záznamů</returns>
		public static Dictionary<int, T> GetDictionary<T>(string sqlCommand, int timeOut) where T : new()
		{
			return _GetDictionary<T>(sqlCommand, null, timeOut, null);
		}
		/// <summary>
		/// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
		/// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
		/// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
		/// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
		/// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <returns>Seznam záznamů</returns>
		public static Dictionary<int, T> GetDictionary<T>(string sqlCommand, SqlParameterCollection parameters) where T : new()
		{
			return _GetDictionary<T>(sqlCommand, parameters, 0, null);
		}
		/// <summary>
		/// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
		/// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
		/// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
		/// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
		/// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <returns>Seznam záznamů</returns>
		public static Dictionary<int, T> GetDictionary<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut) where T : new()
		{
			return _GetDictionary<T>(sqlCommand, parameters, timeOut, null);
		}
        /// <summary>
        /// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
        /// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
        /// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
        /// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
        /// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static Dictionary<int, T> GetDictionary<T>(string sqlCommand, DataConnectType connectType) where T : new()
        {
            return _GetDictionary<T>(sqlCommand, null, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
        /// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
        /// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
        /// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
        /// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static Dictionary<int, T> GetDictionary<T>(string sqlCommand, int timeOut, DataConnectType connectType) where T : new()
        {
            return _GetDictionary<T>(sqlCommand, null, timeOut, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
        /// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
        /// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
        /// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
        /// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static Dictionary<int, T> GetDictionary<T>(string sqlCommand, SqlParameterCollection parameters, DataConnectType connectType) where T : new()
        {
            return _GetDictionary<T>(sqlCommand, parameters, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
        /// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
        /// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
        /// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
        /// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static Dictionary<int, T> GetDictionary<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnectType connectType) where T : new()
        {
            return _GetDictionary<T>(sqlCommand, parameters, timeOut, _GetConnector(connectType));
        }
		/// <summary>
		/// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
		/// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
		/// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
		/// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
		/// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static Dictionary<int, T> GetDictionary<T>(string sqlCommand, DataConnector connector) where T : new()
		{
			return _GetDictionary<T>(sqlCommand, null, 0, connector);
		}
		/// <summary>
		/// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
		/// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
		/// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
		/// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
		/// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static Dictionary<int, T> GetDictionary<T>(string sqlCommand, int timeOut, DataConnector connector) where T : new()
		{
			return _GetDictionary<T>(sqlCommand, null, timeOut, connector);
		}
		/// <summary>
		/// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
		/// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
		/// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
		/// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
		/// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static Dictionary<int, T> GetDictionary<T>(string sqlCommand, SqlParameterCollection parameters, DataConnector connector) where T : new()
		{
			return _GetDictionary<T>(sqlCommand, parameters, 0, connector);
		}
		/// <summary>
		/// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
		/// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
		/// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
		/// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
		/// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static Dictionary<int, T> GetDictionary<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnector connector) where T : new()
		{
			return _GetDictionary<T>(sqlCommand, parameters, timeOut, connector);
		}
		/// <summary>
		/// Načte slovník záznamů. Slovník je automaticky indexován (Dictionary.Key) podle hodnoty RecordNumber z načteného záznamu.
		/// To platí pouze tehdy, pokud generická třída je potomkem třídy RecordCls (která implementuje property get Int32 RecordNumber).
		/// Rovněž je třeba zajistit (konstrukcí SQL SELECTU), aby v načítaných datech nebyly duplicitní hodnoty klíče.
		/// Pokud generická třída není potomkem RecordCls, pak jako Key je použito číslo řádky, počínaje 1.
		/// Záznamy v Dictionary jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		private static Dictionary<int, T> _GetDictionary<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnector connector) where T : new()
		{
			// Pokud není zadán explicitní konektor na data, použije se výchozí.
			if (connector == null) connector = DataConnect.CurrentConnect;

			Dictionary<int, T> result = new Dictionary<int, T>();
            using (var scope = Steward.TraceScopeBegin("Db_Layer", "GetDictionary", "SQL", connector.ConnectType.ToString(), sqlCommand))
            {
                FieldMapperLoad map = null;       // Mapu vytvořím až po otevření readeru
                int recordCounter = 0;
                int recordNumber = 0;
                try
                {
                    using (DataCommand command = connector.CreateCommand(sqlCommand, parameters, timeOut))
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            if (map == null)
                                map = FieldMapperLoad.GetMap(typeof(T), reader);

                            recordCounter++;
                            T record = _CreateRecord<T>(reader, map, out recordNumber);
                            if (recordNumber == 0) recordNumber = recordCounter;

                            result.Add(recordNumber, record);
                        }
                    }
                }
                catch (SqlException exc)
                {
                    throw new SqdException(exc.Message + Environment.NewLine + sqlCommand, exc);
                }
                scope.User = new string[] { result.Count.ToString() };
            }
			return result;
		}
		#endregion
		#region Čtení dat - GetRecord
		/// <summary>
		/// Načte jeden záznam. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <returns>Seznam záznamů</returns>
		public static T GetRecord<T>(string sqlCommand) where T : new()
		{
			return _GetRecord<T>(sqlCommand, null, 0, null);
		}
		/// <summary>
		/// Načte jeden záznam. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <returns>Seznam záznamů</returns>
		public static T GetRecord<T>(string sqlCommand, int timeOut) where T : new()
		{
			return _GetRecord<T>(sqlCommand, null, timeOut, null);
		}
		/// <summary>
		/// Načte jeden záznam. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <returns>Seznam záznamů</returns>
		public static T GetRecord<T>(string sqlCommand, SqlParameterCollection parameters) where T : new()
		{
			return _GetRecord<T>(sqlCommand, parameters, 0, null);
		}
		/// <summary>
		/// Načte jeden záznam. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <returns>Seznam záznamů</returns>
		public static T GetRecord<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut) where T : new()
		{
			return _GetRecord<T>(sqlCommand, parameters, timeOut, null);
		}
        /// <summary>
        /// Načte jeden záznam. Seznam je v tom pořadí, ve kterém byla data načítána.
        /// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static T GetRecord<T>(string sqlCommand, DataConnectType connectType) where T : new()
        {
            return _GetRecord<T>(sqlCommand, null, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte jeden záznam. Seznam je v tom pořadí, ve kterém byla data načítána.
        /// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static T GetRecord<T>(string sqlCommand, int timeOut, DataConnectType connectType) where T : new()
        {
            return _GetRecord<T>(sqlCommand, null, timeOut, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte jeden záznam. Seznam je v tom pořadí, ve kterém byla data načítána.
        /// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static T GetRecord<T>(string sqlCommand, SqlParameterCollection parameters, DataConnectType connectType) where T : new()
        {
            return _GetRecord<T>(sqlCommand, parameters, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte jeden záznam. Seznam je v tom pořadí, ve kterém byla data načítána.
        /// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns>Seznam záznamů</returns>
        public static T GetRecord<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnectType connectType) where T : new()
        {
            return _GetRecord<T>(sqlCommand, parameters, timeOut, _GetConnector(connectType));
        }
        /// <summary>
		/// Načte jeden záznam. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static T GetRecord<T>(string sqlCommand, DataConnector connector) where T : new()
		{
			return _GetRecord<T>(sqlCommand, null, 0, connector);
		}
		/// <summary>
		/// Načte jeden záznam. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static T GetRecord<T>(string sqlCommand, int timeOut, DataConnector connector) where T : new()
		{
			return _GetRecord<T>(sqlCommand, null, timeOut, connector);
		}
		/// <summary>
		/// Načte jeden záznam. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static T GetRecord<T>(string sqlCommand, SqlParameterCollection parameters, DataConnector connector) where T : new()
		{
			return _GetRecord<T>(sqlCommand, parameters, 0, connector);
		}
		/// <summary>
		/// Načte jeden záznam. Seznam je v tom pořadí, ve kterém byla data načítána.
		/// Záznamy jsou třídy T (generikum), data pocházejí z daného selectu.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		public static T GetRecord<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnector connector) where T : new()
		{
			return _GetRecord<T>(sqlCommand, parameters, timeOut, connector);
		}
		/// <summary>
		/// Načte jeden první záznam.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		private static T _GetRecord<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnector connector) where T : new()
		{
			// Pokud není zadán explicitní konektor na data, použije se výchozí.
			if (connector == null) connector = DataConnect.CurrentConnect;

			T result = default(T);            // Tady nebude vytvářen objekt new(): mám vrátit jednotlivý záznam, a pokud nebude vrácena žádná věta, pak vrátím null.

            using (var scope = Steward.TraceScopeBegin("Db_Layer", "GetRecord", "SQL", connector.ConnectType.ToString(), sqlCommand))
            {
                FieldMapperLoad map = null;       // Mapu vytvořím až po otevření readeru
                try
                {
                    using (DataCommand command = connector.CreateCommand(sqlCommand, parameters, timeOut))
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        if (!reader.HasRows)
                        {
                            reader.Close();
                        }
                        else
                        {
                            if (map == null)
                                map = FieldMapperLoad.GetMap(typeof(T), reader);

                            while (reader.Read())
                            {
                                result = _CreateRecord<T>(reader, map);
                                reader.Close();
                                break;
                            }
                        }
                    }
                }
                catch (SqlException exc)
                {
                    throw new SqdException(exc.Message + Environment.NewLine + sqlCommand, exc);
                }
                scope.User = new string[] { (result == null ? "null" : "ok") };
            }
			return result;
		}
		#endregion
		#region Čtení dat - LoadIntoRecord
		/// <summary>
		/// Do předaného objektu načte data z databáze s pomocí daného selectu.
		/// </summary>
		/// <param name="record">Cílový záznam</param>
		/// <param name="sqlCommand">Definice selectu</param>
		public static void LoadIntoRecord(object record, string sqlCommand)
		{
			_LoadIntoRecord(record, sqlCommand, null, 0, null);
		}
		/// <summary>
		/// Do předaného objektu načte data z databáze s pomocí daného selectu.
		/// </summary>
		/// <param name="record">Cílový záznam</param>
		/// <param name="sqlCommand">Definice selectu</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		public static void LoadIntoRecord(object record, string sqlCommand, int timeOut)
		{
			_LoadIntoRecord(record, sqlCommand, null, timeOut, null);
		}
		/// <summary>
		/// Do předaného objektu načte data z databáze s pomocí daného selectu.
		/// </summary>
		/// <param name="record">Cílový záznam</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="sqlCommand">Definice selectu</param>
		public static void LoadIntoRecord(object record, string sqlCommand, SqlParameterCollection parameters)
		{
			_LoadIntoRecord(record, sqlCommand, parameters, 0, null);
		}
		/// <summary>
		/// Do předaného objektu načte data z databáze s pomocí daného selectu.
		/// </summary>
		/// <param name="record">Cílový záznam</param>
		/// <param name="sqlCommand">Definice selectu</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		public static void LoadIntoRecord(object record, string sqlCommand, SqlParameterCollection parameters, int timeOut)
		{
			_LoadIntoRecord(record, sqlCommand, parameters, timeOut, null);
		}
        /// <summary>
        /// Do předaného objektu načte data z databáze s pomocí daného selectu.
        /// </summary>
        /// <param name="record">Cílový záznam</param>
        /// <param name="sqlCommand">Definice selectu</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void LoadIntoRecord(object record, string sqlCommand, DataConnectType connectType)
        {
            _LoadIntoRecord(record, sqlCommand, null, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Do předaného objektu načte data z databáze s pomocí daného selectu.
        /// </summary>
        /// <param name="record">Cílový záznam</param>
        /// <param name="sqlCommand">Definice selectu</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void LoadIntoRecord(object record, string sqlCommand, int timeOut, DataConnectType connectType)
        {
            _LoadIntoRecord(record, sqlCommand, null, timeOut, _GetConnector(connectType));
        }
        /// <summary>
        /// Do předaného objektu načte data z databáze s pomocí daného selectu.
        /// </summary>
        /// <param name="record">Cílový záznam</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="sqlCommand">Definice selectu</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void LoadIntoRecord(object record, string sqlCommand, SqlParameterCollection parameters, DataConnectType connectType)
        {
            _LoadIntoRecord(record, sqlCommand, parameters, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Do předaného objektu načte data z databáze s pomocí daného selectu.
        /// </summary>
        /// <param name="record">Cílový záznam</param>
        /// <param name="sqlCommand">Definice selectu</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void LoadIntoRecord(object record, string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnectType connectType)
        {
            _LoadIntoRecord(record, sqlCommand, parameters, timeOut, _GetConnector(connectType));
        }
        /// <summary>
		/// Do předaného objektu načte data z databáze s pomocí daného selectu.
		/// </summary>
		/// <param name="record">Cílový záznam</param>
		/// <param name="sqlCommand">Definice selectu</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void LoadIntoRecord(object record, string sqlCommand, DataConnector connector)
		{
			_LoadIntoRecord(record, sqlCommand, null, 0, connector);
		}
		/// <summary>
		/// Do předaného objektu načte data z databáze s pomocí daného selectu.
		/// </summary>
		/// <param name="record">Cílový záznam</param>
		/// <param name="sqlCommand">Definice selectu</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void LoadIntoRecord(object record, string sqlCommand, int timeOut, DataConnector connector)
		{
			_LoadIntoRecord(record, sqlCommand, null, timeOut, connector);
		}
		/// <summary>
		/// Do předaného objektu načte data z databáze s pomocí daného selectu.
		/// </summary>
		/// <param name="record">Cílový záznam</param>
		/// <param name="sqlCommand">Definice selectu</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void LoadIntoRecord(object record, string sqlCommand, SqlParameterCollection parameters, DataConnector connector)
		{
			_LoadIntoRecord(record, sqlCommand, parameters, 0, connector);
		}
		/// <summary>
		/// Do předaného objektu načte data z databáze s pomocí daného selectu.
		/// </summary>
		/// <param name="record">Cílový záznam</param>
		/// <param name="sqlCommand">Definice selectu</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void LoadIntoRecord(object record, string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnector connector)
		{
			_LoadIntoRecord(record, sqlCommand, parameters, timeOut, connector);
		}
		/// <summary>
		/// Načte jeden první záznam.
		/// </summary>
		/// <param name="record">Objekt, do něhož se data načtou. 
		/// Objekt na vstupu nesmí být null, protože funkce si jej nevytváří. 
		/// Musí být konkrétního typu, jinak se do něj data nenačtou (neprovede se jeho detekce = mapování).</param>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns>Seznam záznamů</returns>
		private static void _LoadIntoRecord(object record, string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnector connector)
		{
			// Pokud není zadán explicitní konektor na data, použije se výchozí.
			if (connector == null) connector = DataConnect.CurrentConnect;

			FieldMapperLoad map = null;       // Mapu vytvořím až po otevření readeru
			try
			{
                using (var scope = Steward.TraceScopeBegin("Db_Layer", "LoadIntoRecord", "SQL", connector.ConnectType.ToString(), sqlCommand))
                using (DataCommand command = connector.CreateCommand(sqlCommand, parameters, timeOut))
                using (SqlDataReader reader = command.ExecuteReader())
				{
					if (map == null)
						map = FieldMapperLoad.GetMap(record.GetType(), reader);

					while (reader.Read())
					{
						int recordNumber;
						_FillRecord(record, reader, map, out recordNumber);
						reader.Close();
						break;
					}
				}
			}
			catch (SqlException exc)
			{
				throw new SqdException(exc.Message + Environment.NewLine + sqlCommand, exc);
			}
		}
		#endregion
		#region Čtení dat - GetItem
		/// <summary>
		/// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <returns></returns>
		public static T GetItem<T>(string sqlCommand) // where T : new()
		{
			return _GetItem<T>(sqlCommand, null, 0, null);
		}
		/// <summary>
		/// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <returns></returns>
		public static T GetItem<T>(string sqlCommand, int timeOut) // where T : new()
		{
			return _GetItem<T>(sqlCommand, null, timeOut, null);
		}
		/// <summary>
		/// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <returns></returns>
		public static T GetItem<T>(string sqlCommand, SqlParameterCollection parameters) // where T : new()
		{
			return _GetItem<T>(sqlCommand, parameters, 0, null);
		}
		/// <summary>
		/// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <returns></returns>
		public static T GetItem<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut) // where T : new()
		{
			return _GetItem<T>(sqlCommand, parameters, timeOut, null);
		}
        /// <summary>
        /// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static T GetItem<T>(string sqlCommand, DataConnectType connectType)
        {
            return _GetItem<T>(sqlCommand, null, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static T GetItem<T>(string sqlCommand, int timeOut, DataConnectType connectType)
        {
            return _GetItem<T>(sqlCommand, null, timeOut, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static T GetItem<T>(string sqlCommand, SqlParameterCollection parameters, DataConnectType connectType)
        {
            return _GetItem<T>(sqlCommand, parameters, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static T GetItem<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnectType connectType)
        {
            return _GetItem<T>(sqlCommand, parameters, timeOut, _GetConnector(connectType));
        }
        /// <summary>
		/// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		public static T GetItem<T>(string sqlCommand, DataConnector connector) // where T : new()
		{
			return _GetItem<T>(sqlCommand, null, 0, connector);
		}
		/// <summary>
		/// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		public static T GetItem<T>(string sqlCommand, int timeOut, DataConnector connector) // where T : new()
		{
			return _GetItem<T>(sqlCommand, null, timeOut, connector);
		}
		/// <summary>
		/// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		public static T GetItem<T>(string sqlCommand, SqlParameterCollection parameters, DataConnector connector) // where T : new()
		{
			return _GetItem<T>(sqlCommand, parameters, 0, connector);
		}
		/// <summary>
		/// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		public static T GetItem<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnector connector) // where T : new()
		{
			return _GetItem<T>(sqlCommand, parameters, timeOut, connector);
		}
		/// <summary>
		/// Načte jednu hodnotu. Načte hodnotu z prvního sloupce z prvního řádku.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		/// <returns></returns>
		private static T _GetItem<T>(string sqlCommand, SqlParameterCollection parameters, int timeOut, DataConnector connector) //where T : new()
		{
			// Pokud není zadán explicitní konektor na data, použije se výchozí.
			if (connector == null) connector = DataConnect.CurrentConnect;

			T result = default(T);
			Type typeT = typeof(T);
            bool isPrimitive = Type.Equals(typeT, typeof(object)) || typeT.IsPrimitive;                      // true pokud je T object nebo primitivní typ
			bool isSqlType = typeT.FullName.Contains("System.Data.SqlTypes.Sql") && typeT.IsValueType;       // Struktura typu "Sql*"
			bool isString = typeT.Equals(typeof(String));

			if (isPrimitive || isSqlType || isString)
			{
				try
				{
                    using (var scope = Steward.TraceScopeBegin("Db_Layer", "ExecuteReader", "SQL", connector.ConnectType.ToString(), sqlCommand))
                    using (DataCommand command = connector.CreateCommand(sqlCommand, parameters, timeOut))
                    using (SqlDataReader reader = command.ExecuteReader())
					{
						while (reader.Read())
						{
							if (reader.FieldCount > 0)
							{
								if (!reader.IsDBNull(0))
								{
									if (isPrimitive)
										result = (T)reader.GetValue(0);
									else if (isString)
										result = (T)reader.GetValue(0);
									else if (isSqlType)
										result = (T)reader.GetValue(0);
								}
							}
							break;
						}
						reader.Close();
					}
				}
				catch (SqlException exc)
				{
					throw new SqdException(exc.Message + Environment.NewLine + sqlCommand, exc);
				}
			}
			else
				Throw.SysError(MessageInfo.Get("Metoda LoadData.GetItem smí být použita pouze na primitivní a Sql datové typy typy."));


			return result;
		}
		#endregion
		#region Čtení dat - OpenInputStream
		/// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target) where T : new()
		{
			_OpenInputStream(sqlCommand, target, null, -1, null, null);
		}
		/// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		/// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
		public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, object userData) where T : new()
		{
			_OpenInputStream(sqlCommand, target, null, -1, userData, null);
		}
		/// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
		public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, int timeOut, object userData) where T : new()
		{
			_OpenInputStream(sqlCommand, target, null, timeOut, userData, null);
		}
		/// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, SqlParameterCollection parameters) where T : new()
		{
			_OpenInputStream(sqlCommand, target, parameters, -1, null, null);
		}
		/// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
		public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, SqlParameterCollection parameters, object userData) where T : new()
		{
			_OpenInputStream(sqlCommand, target, parameters, -1, userData, null);
		}
		/// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
		public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, SqlParameterCollection parameters, int timeOut, object userData) where T : new()
		{
			_OpenInputStream(sqlCommand, target, parameters, timeOut, userData, null);
		}
        /// <summary>
        /// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
        /// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
        /// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
        /// Zpracovatelská metoda je předána jako delegát.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, DataConnectType connectType) where T : new()
        {
            _OpenInputStream(sqlCommand, target, null, -1, null, _GetConnector(connectType));
        }
        /// <summary>
        /// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
        /// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
        /// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
        /// Zpracovatelská metoda je předána jako delegát.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
        /// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, object userData, DataConnectType connectType) where T : new()
        {
            _OpenInputStream(sqlCommand, target, null, -1, userData, _GetConnector(connectType));
        }
        /// <summary>
        /// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
        /// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
        /// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
        /// Zpracovatelská metoda je předána jako delegát.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, int timeOut, object userData, DataConnectType connectType) where T : new()
        {
            _OpenInputStream(sqlCommand, target, null, timeOut, userData, _GetConnector(connectType));
        }
        /// <summary>
        /// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
        /// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
        /// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
        /// Zpracovatelská metoda je předána jako delegát.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, SqlParameterCollection parameters, DataConnectType connectType) where T : new()
        {
            _OpenInputStream(sqlCommand, target, parameters, -1, null, _GetConnector(connectType));
        }
        /// <summary>
        /// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
        /// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
        /// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
        /// Zpracovatelská metoda je předána jako delegát.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, SqlParameterCollection parameters, object userData, DataConnectType connectType) where T : new()
        {
            _OpenInputStream(sqlCommand, target, parameters, -1, userData, _GetConnector(connectType));
        }
        /// <summary>
        /// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
        /// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
        /// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
        /// Zpracovatelská metoda je předána jako delegát.
        /// </summary>
        /// <param name="sqlCommand">SQL SELECT command</param>
        /// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, SqlParameterCollection parameters, int timeOut, object userData, DataConnectType connectType) where T : new()
        {
            _OpenInputStream(sqlCommand, target, parameters, timeOut, userData, _GetConnector(connectType));
        }
        /// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, DataConnector connector) where T : new()
		{
			_OpenInputStream(sqlCommand, target, null, -1, null, connector);
		}
		/// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		/// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, object userData, DataConnector connector) where T : new()
		{
			_OpenInputStream(sqlCommand, target, null, -1, userData, connector);
		}
		/// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, int timeOut, object userData, DataConnector connector) where T : new()
		{
			_OpenInputStream(sqlCommand, target, null, timeOut, userData, connector);
		}
		/// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, SqlParameterCollection parameters, DataConnector connector) where T : new()
		{
			_OpenInputStream(sqlCommand, target, parameters, -1, null, connector);
		}
		/// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, SqlParameterCollection parameters, object userData, DataConnector connector) where T : new()
		{
			_OpenInputStream(sqlCommand, target, parameters, -1, userData, connector);
		}
		/// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, SqlParameterCollection parameters, int timeOut, object userData, DataConnector connector) where T : new()
		{
			_OpenInputStream(sqlCommand, target, parameters, timeOut, userData, connector);
		}
		/// <summary>
		/// Zajistí průběžné načítání dat z daného SQL SELECTU, a jejich okamžité odesílání do zpracovatelské metody.
		/// Načítaná data nejsou tedy ukládána, ale jsou určena k okamžitému zpracování.
		/// Pozor: v době zpracování dat je aktivní SQL READER, není tedy dost dobře možné defaultně číst/zapisovat data dalším SQL kanálem.
		/// Zpracovatelská metoda je předána jako delegát.
		/// </summary>
		/// <param name="sqlCommand">SQL SELECT command</param>
		/// <param name="target">Metoda, která postupně přijímá načtené záznamy jeden po druhém a zpracovává si je po svém.</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="userData">Libovolný objekt, bude předáván do target metody v e.Userdata</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		private static void _OpenInputStream<T>(string sqlCommand, LoadInputStreamDelegate<T> target, SqlParameterCollection parameters, int timeOut, object userData, DataConnector connector) where T : new()
		{
			// Pokud není zadán explicitní konektor na data, použije se výchozí.
			if (connector == null) connector = DataConnect.CurrentConnect;

			FieldMapperLoad map = null;       // Mapu vytvořím až po otevření readeru
			try
			{
                using (var scope = Steward.TraceScopeBegin("Db_Layer", "OpenInputStream", "SQL", connector.ConnectType.ToString(), sqlCommand))
                using (DataCommand command = DataConnect.CreateCommand(sqlCommand, timeOut))
                using (SqlDataReader reader = command.ExecuteReader())
				{
					LoadInputStreamEventArgs<T> e = new LoadInputStreamEventArgs<T>(userData);
					while (reader.Read())
					{
						if (map == null)
							map = FieldMapperLoad.GetMap(typeof(T), reader);

						e.Record = _CreateRecord<T>(reader, map);
						e.Row++;
						target(reader, e);
						if (e.Cancel) break;
					}
				}
			}
			catch (SqlException exc)
			{
				throw new SqdException(exc.Message + Environment.NewLine + sqlCommand, exc);
			}
		}
		/// <summary>
		/// Deklarace delegáta, který bude obsluhovat příjem každého jednoho záznamu z metody Db_Layer.OpenInputStream()
		/// Delegát obdrží argument e, v němž je v proměnné Record uložen záznam, který byl právě načten z databáze.
		/// Záznamy se nikam neuchovávají, metoda OpenInputStream() je jen průchozí z databáze do tohoto delegáta. 
		/// Co se v něm s daty stane, je jen na něm.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		public delegate void LoadInputStreamDelegate<T>(object sender, LoadInputStreamEventArgs<T> e) where T : new();
		/// <summary>
		/// Argument pro průběžné načítání dat
		/// </summary>
		public class LoadInputStreamEventArgs<T> : EventArgs where T : new()
		{
			/// <summary>
			/// Konstruktor
			/// </summary>
			/// <param name="userData"></param>
			public LoadInputStreamEventArgs(object userData)
			{
				Row = 0;
				Record = default(T);
				UserData = userData;
				Cancel = false;
			}
			/// <summary>
			/// Číslo řádku, počínaje 1
			/// </summary>
			public int Row;
			/// <summary>
			/// Záznam s daty
			/// </summary>
			public T Record;
			/// <summary>
			/// Uživatelova data
			/// </summary>
			public object UserData;
			/// <summary>
			/// Příznak, že (target) metoda chce přerušit načítání
			/// </summary>
			public bool Cancel;
		}
		#endregion
        #region Čtení dat - otevření vstupního kanálu SqlDataReader
        /// <summary>
        /// Načte data skrz DataReader. 
        /// Předává se SQL dotaz, akce provedená na začátku čtení (typicky zpracuje sloupce) a akce prováděná pro každý řádek.
        /// Volitelně se předávají paramery, timeout a datakonektor.
        /// </summary>
        /// <param name="sqlCommand"></param>
        /// <param name="onBegin"></param>
        /// <param name="onEveryRow"></param>
        public static void ReadFromDataReader(string sqlCommand, Action<SqlDataReader> onBegin, Func<SqlDataReader, bool> onEveryRow)
        {
            _ReadFromDataReader(sqlCommand, onBegin, onEveryRow, null, 0, null);
        }
        /// <summary>
        /// Načte data skrz DataReader. 
        /// Předává se SQL dotaz, akce provedená na začátku čtení (typicky zpracuje sloupce) a akce prováděná pro každý řádek.
        /// Volitelně se předávají paramery, timeout a datakonektor.
        /// </summary>
        /// <param name="sqlCommand"></param>
        /// <param name="onBegin"></param>
        /// <param name="onEveryRow"></param>
        /// <param name="parameters"></param>
        public static void ReadFromDataReader(string sqlCommand, Action<SqlDataReader> onBegin, Func<SqlDataReader, bool> onEveryRow, ParameterCollection parameters)
        {
            _ReadFromDataReader(sqlCommand, onBegin, onEveryRow, parameters, 0, null);
        }
        /// <summary>
        /// Načte data skrz DataReader. 
        /// Předává se SQL dotaz, akce provedená na začátku čtení (typicky zpracuje sloupce) a akce prováděná pro každý řádek.
        /// Volitelně se předávají paramery, timeout a datakonektor.
        /// </summary>
        /// <param name="sqlCommand"></param>
        /// <param name="onBegin"></param>
        /// <param name="onEveryRow"></param>
        /// <param name="parameters"></param>
        /// <param name="timeOut"></param>
        public static void ReadFromDataReader(string sqlCommand, Action<SqlDataReader> onBegin, Func<SqlDataReader, bool> onEveryRow, ParameterCollection parameters, int timeOut)
        {
            _ReadFromDataReader(sqlCommand, onBegin, onEveryRow, parameters, timeOut, null);
        }
        /// <summary>
        /// Načte data skrz DataReader. 
        /// Předává se SQL dotaz, akce provedená na začátku čtení (typicky zpracuje sloupce) a akce prováděná pro každý řádek.
        /// Volitelně se předávají paramery, timeout a datakonektor.
        /// </summary>
        /// <param name="sqlCommand"></param>
        /// <param name="onBegin"></param>
        /// <param name="onEveryRow"></param>
        /// <param name="parameters"></param>
        /// <param name="timeOut"></param>
        /// <param name="connector"></param>
        public static void ReadFromDataReader(string sqlCommand, Action<SqlDataReader> onBegin, Func<SqlDataReader, bool> onEveryRow, ParameterCollection parameters, int timeOut, DataConnector connector)
        {
            _ReadFromDataReader(sqlCommand, onBegin, onEveryRow, parameters, timeOut, connector);
        }
        private static void _ReadFromDataReader(string sqlCommand, Action<SqlDataReader> onBegin, Func<SqlDataReader, bool> onEveryRow, ParameterCollection parameters, int timeOut, DataConnector connector)
        {
            // Pokud není zadán explicitní konektor na data, použije se výchozí.
            if (connector == null) connector = DataConnect.CurrentConnect;

            try
            {
                using (var scope = Steward.TraceScopeBegin("Db_Layer", "ReadFromDataReader", "SQL", connector.ConnectType.ToString(), sqlCommand))
                using (DataCommand command = DataConnect.CreateCommand(sqlCommand, timeOut))
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    if (parameters != null) parameters.ApplyToSqlCommand(command);
                    onBegin(reader);
                    if (reader.HasRows)
                    {
                        while (reader.Read())
                        {
                            bool goNext = onEveryRow(reader);
                            if (!goNext)
                                break;
                        }
                    }
                }
            }
            catch (SqlException exc)
            {
                throw new SqdException(exc.Message + Environment.NewLine + sqlCommand, exc);
            }
        }
        #endregion
        #region Čtení dat - do System.Data.DataTable
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sqlCmd)
        {
            return _GetDataTable(sqlCmd, null, 0, null);
        }
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sqlCmd, int timeOut)
        {
            return _GetDataTable(sqlCmd, null, timeOut, null);
        }
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sqlCmd, SqlParameterCollection parameters)
        {
            return _GetDataTable(sqlCmd, parameters, 0, null);
        }
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sqlCmd, SqlParameterCollection parameters, int timeOut)
        {
            return _GetDataTable(sqlCmd, parameters, timeOut, null);
        }
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sqlCmd, DataConnectType connectType)
        {
            return _GetDataTable(sqlCmd, null, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sqlCmd, int timeOut, DataConnectType connectType)
        {
            return _GetDataTable(sqlCmd, null, timeOut, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sqlCmd, SqlParameterCollection parameters, DataConnectType connectType)
        {
            return _GetDataTable(sqlCmd, parameters, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sqlCmd, SqlParameterCollection parameters, int timeOut, DataConnectType connectType)
        {
            return _GetDataTable(sqlCmd, parameters, timeOut, _GetConnector(connectType));
        }
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sqlCmd, DataConnector connector)
        {
            return _GetDataTable(sqlCmd, null, 0, connector);
        }
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sqlCmd, int timeOut, DataConnector connector)
        {
            return _GetDataTable(sqlCmd, null, timeOut, connector);
        }
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sqlCmd, SqlParameterCollection parameters, DataConnector connector)
        {
            return _GetDataTable(sqlCmd, parameters, 0, connector);
        }
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
        /// <returns></returns>
        public static DataTable GetDataTable(string sqlCmd, SqlParameterCollection parameters, int timeOut, DataConnector connector)
        {
            return _GetDataTable(sqlCmd, parameters, timeOut, connector);
        }
        /// <summary>
        /// Načte a vrátí System.Data.DataTable z aktuálního připojení, daným SQL SELECTEM.
        /// </summary>
        /// <param name="sqlCmd">SQL SELECT</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
        /// <returns></returns>
        private static DataTable _GetDataTable(string sqlCmd, SqlParameterCollection parameters, int timeOut, DataConnector connector)
        {
            // Pokud není zadán explicitní konektor na data, použije se výchozí.
            if (connector == null) connector = DataConnect.CurrentConnect;

            DataTable table = new DataTable();
            table.Constraints.Clear();
            using (var scope = Steward.TraceScopeBegin("Db_Layer", "GetDataTable", "SQL", connector.ConnectType.ToString(), sqlCmd))
            using (DataCommand command = connector.CreateCommand(sqlCmd, parameters, timeOut))
            using (SqlDataReader reader = command.ExecuteReader())
            {
                table.BeginLoadData();
                table.Constraints.Clear();
                table.Load(reader, LoadOption.OverwriteChanges, _GetDataTableErrorHandler);
                table.EndLoadData();
            }
            return table;
        }
        private static void _GetDataTableErrorHandler(object sender, FillErrorEventArgs e)
        {
            e.Continue = true;
        }
        #endregion
        #region Čtení dat - o záznamech
        /// <summary>
        /// Vrací referenci daného subjektu
        /// </summary>
        /// <param name="recordNumber"></param>
        /// <returns></returns>
        public static string GetReference(Int32? recordNumber)
        {
            if (!recordNumber.HasValue) return null;
            string sql = "SELECT reference_subjektu FROM lcs.subjekty WHERE cislo_subjektu = " + recordNumber.Value.ToString();
            return GetItem<string>(sql);
        }
        /// <summary>
        /// Vrací název daného subjektu
        /// </summary>
        /// <param name="recordNumber"></param>
        /// <returns></returns>
        public static string GetNazev(Int32? recordNumber)
        {
            if (!recordNumber.HasValue) return null;
            string sql = "SELECT nazev_subjektu FROM lcs.subjekty WHERE cislo_subjektu = " + recordNumber.Value.ToString();
            return GetItem<string>(sql);
        }
        /// <summary>
        /// Vrací celý záznam subjektu
        /// </summary>
        /// <param name="recordNumber"></param>
        /// <returns></returns>
        public static SubjectCls GetSubject(Int32? recordNumber)
        {
            if (!recordNumber.HasValue) return null;
            string sql = "SELECT * FROM lcs.subjekty WHERE cislo_subjektu = " + recordNumber.Value.ToString();
            return GetRecord<SubjectCls>(sql);
        }
        #endregion
        #region Podpora TEMP tabulek
        /// <summary>
        /// <para>
		/// Zajistí vytvoření TEMP tabulky.
		/// Pokud tabulka existuje, bude nejprve zrušena.
        /// DROP této tamp tabulky je na volající metodě, jinak zůstane v databázi až do konce Connection.
        /// </para>
        /// <para>
        /// Na rozdíl od toho existuje metoda TempTableOpen(), která vrací IDisposable objekt, který při svém Dispose tuto tabulku uvolňuje.
        /// </para>
		/// </summary>
		/// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
		/// <param name="createCommand">SQL příkaz pro její vytvoření. Může to být CREATE TABLE #tempname (), anebo SELECT * INTO #tempname FROM...</param>
		public static void TempTableCreate(string tableName, string createCommand)
		{
			_TempTableCreate(tableName, createCommand, null, 0, null);
		}
 		/// <summary>
        /// <para>
        /// Zajistí vytvoření TEMP tabulky.
        /// Pokud tabulka existuje, bude nejprve zrušena.
        /// DROP této tamp tabulky je na volající metodě, jinak zůstane v databázi až do konce Connection.
        /// </para>
        /// <para>
        /// Na rozdíl od toho existuje metoda TempTableOpen(), která vrací IDisposable objekt, který při svém Dispose tuto tabulku uvolňuje.
        /// </para>
        /// </summary>
        /// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
        /// <param name="createCommand">SQL příkaz pro její vytvoření. Může to být CREATE TABLE #tempname (), anebo SELECT * INTO #tempname FROM...</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void TempTableCreate(string tableName, string createCommand, DataConnectType connectType)
        {
            _TempTableCreate(tableName, createCommand, null, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// <para>
        /// Zajistí vytvoření TEMP tabulky.
        /// Pokud tabulka existuje, bude nejprve zrušena.
        /// DROP této tamp tabulky je na volající metodě, jinak zůstane v databázi až do konce Connection.
        /// </para>
        /// <para>
        /// Na rozdíl od toho existuje metoda TempTableOpen(), která vrací IDisposable objekt, který při svém Dispose tuto tabulku uvolňuje.
        /// </para>
        /// </summary>
		/// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
		/// <param name="createCommand">SQL příkaz pro její vytvoření. Může to být CREATE TABLE #tempname (), anebo SELECT * INTO #tempname FROM...</param>
		public static void TempTableCreate(string tableName, string createCommand, DataConnector connector)
		{
			_TempTableCreate(tableName, createCommand, null, 0, connector);
		}
		/// <summary>
        /// <para>
        /// Zajistí vytvoření TEMP tabulky.
        /// Pokud tabulka existuje, bude nejprve zrušena.
        /// DROP této tamp tabulky je na volající metodě, jinak zůstane v databázi až do konce Connection.
        /// </para>
        /// <para>
        /// Na rozdíl od toho existuje metoda TempTableOpen(), která vrací IDisposable objekt, který při svém Dispose tuto tabulku uvolňuje.
        /// </para>
        /// </summary>
		/// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
		/// <param name="createCommand">SQL příkaz pro její vytvoření. Může to být CREATE TABLE #tempname (), anebo SELECT * INTO #tempname FROM...</param>
		private static void _TempTableCreate(string tableName, string createCommand, SqlParameterCollection parameters, int timeOut, DataConnector connector)
		{
			// Pokud není zadán explicitní konektor na data, použije se výchozí.
			if (connector == null) connector = DataConnect.CurrentConnect;

			string sqlCommand = _GetTempTableDropCmd(tableName) + "\r\n\r\n" + createCommand;
            using (var scope = Steward.TraceScopeBegin("Db_Layer", "TempTableCreate", "SQL", connector.ConnectType.ToString(), createCommand))
            using (DataCommand command = connector.CreateCommand(sqlCommand, null, timeOut))
            {
				command.ExecuteNonQuery();
			}
		}
		/// <summary>
        /// <para>
		/// Zajistí vytvoření TEMP tabulky.
		/// Pokud tabulka existuje, bude nejprve zrušena.
        /// </para>
        /// <para>
        /// Pozor: tato metoda vrací IDisposable objekt, který při svém Dispose tuto vytvořenou tabulku uvolňuje!!!
        /// Je tedy nutné tuto metodu volat v using patternu.
        /// </para>
		/// </summary>
		/// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
		/// <param name="createCommand">SQL příkaz pro její vytvoření. Může to být CREATE TABLE #tempname (), anebo SELECT * INTO #tempname FROM...</param>
		public static DbTempTableDisposable TempTableOpen(string tableName, string createCommand)
		{
			return _TempTableOpen(tableName, createCommand, null, 0, null);
		}
		/// <summary>
        /// <para>
        /// Zajistí vytvoření TEMP tabulky.
        /// Pokud tabulka existuje, bude nejprve zrušena.
        /// </para>
        /// <para>
        /// Pozor: tato metoda vrací IDisposable objekt, který při svém Dispose tuto vytvořenou tabulku uvolňuje!!!
        /// Je tedy nutné tuto metodu volat v using patternu.
        /// </para>
        /// </summary>
        /// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
        /// <param name="createCommand">SQL příkaz pro její vytvoření. Může to být CREATE TABLE #tempname (), anebo SELECT * INTO #tempname FROM...</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static DbTempTableDisposable TempTableOpen(string tableName, string createCommand, DataConnectType connectType)
        {
            return _TempTableOpen(tableName, createCommand, null, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// <para>
        /// Zajistí vytvoření TEMP tabulky.
        /// Pokud tabulka existuje, bude nejprve zrušena.
        /// </para>
        /// <para>
        /// Pozor: tato metoda vrací IDisposable objekt, který při svém Dispose tuto vytvořenou tabulku uvolňuje!!!
        /// Je tedy nutné tuto metodu volat v using patternu.
        /// </para>
        /// </summary>
		/// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
		/// <param name="createCommand">SQL příkaz pro její vytvoření. Může to být CREATE TABLE #tempname (), anebo SELECT * INTO #tempname FROM...</param>
		public static DbTempTableDisposable TempTableOpen(string tableName, string createCommand, DataConnector connector)
		{
			return _TempTableOpen(tableName, createCommand, null, 0, connector);
		}
        /// <summary>
		/// Zajistí vytvoření TEMP tabulky.
		/// Pokud tabulka existuje, bude nejprve zrušena.
        /// Pozor: tato metoda vrací IDisposable objekt, který při svém Dispose tuto vytvořenou tabulku uvolňuje!!!
        /// Je tedy nutné tuto metodu volat v using patternu.
		/// </summary>
		/// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
		/// <param name="createCommand">SQL příkaz pro její vytvoření. Může to být CREATE TABLE #tempname (), anebo SELECT * INTO #tempname FROM...</param>
		private static DbTempTableDisposable _TempTableOpen(string tableName, string createCommand, SqlParameterCollection parameters, int timeOut, DataConnector connector)
		{
            _TempTableCreate(tableName, createCommand, parameters, timeOut, connector);
            return new DbTempTableDisposable(tableName, connector);
		}
		/// <summary>
		/// Zajistí smazání TEMP tabulky.
		/// </summary>
		/// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
		public static void TempTableDrop(string tableName)
		{
			_TempTableDrop(tableName, null, 0, null);
		}
        /// <summary>
        /// Zajistí smazání TEMP tabulky.
        /// </summary>
        /// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void TempTableDrop(string tableName, DataConnectType connectType)
        {
            _TempTableDrop(tableName, null, 0, _GetConnector(connectType));
        }
        /// <summary>
		/// Zajistí smazání TEMP tabulky.
		/// </summary>
		/// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
		public static void TempTableDrop(string tableName, DataConnector connector)
		{
			_TempTableDrop(tableName, null, 0, connector);
		}
		/// <summary>
		/// Zajistí smazání TEMP tabulky.
		/// </summary>
		/// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
		private static void _TempTableDrop(string tableName, SqlParameterCollection parameters, int timeOut, DataConnector connector)
		{
			// Pokud není zadán explicitní konektor na data, použije se výchozí.
			if (connector == null) connector = DataConnect.CurrentConnect;

			string sqlCommand = _GetTempTableDropCmd(tableName);
            using (var scope = Steward.TraceScopeBegin("Db_Layer", "TempTableDrop", "SQL", connector.ConnectType.ToString(), tableName))
            using (DataCommand command = DataConnect.CreateCommand(sqlCommand, null, timeOut))
			{
				command.ExecuteNonQuery();
			}
		}
		/// <summary>
		/// Vrátí SQL příkaz pro podmínečný DROP TABLE temp
		/// </summary>
		/// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
		/// <returns></returns>
		public static string GetTempTableDropCmd(string tableName)
		{
			return _GetTempTableDropCmd(tableName);
		}
		/// <summary>
		/// Vrátí SQL příkaz pro podmínečný DROP TABLE temp
		/// </summary>
		/// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
		/// <returns></returns>
		private static string _GetTempTableDropCmd(string tableName)
		{
			string tempName = _GetTempTableName(tableName);
            string sql = @"if (isnull(object_id('tempdb..{{TableName}}'), 0) <> 0)
	exec('drop table {{TableName}}')
";
			sql = sql.Replace("{{TableName}}", tempName);
			return sql;
		}
		/// <summary>
		/// Vrátí ošetřené jméno TEMP tabulky (tj. "#tablename")
		/// </summary>
		/// <param name="tableName">Název TEMP tabulky. Měl by začínat "#" (ale nemusí, program si znak # předsadí sám)</param>
		/// <returns></returns>
		private static string _GetTempTableName(string tableName)
		{
			string tempName = tableName.Replace(" ", "");
			while (tempName.Length > 0 && tempName[0] == '#')
				tempName = tempName.Substring(1);
			return "#" + tempName.Trim();
		}
		#endregion
        #region Detekce existence tabulek a sloupců
        /// <summary>
        /// Zjistí, zda v připojené databázi existuje daná tabulka.
        /// Vrací true / false, nevyhazuje chyby.
        /// </summary>
        /// <param name="owner">Vlastník tabulky, typicky "lcs"</param>
        /// <param name="table">Název tabulky bez vlastníka, například "sk_sklad"</param>
        /// <returns>true = tabulka existuje / false = neexistuje</returns>
        public static bool DbTableExists(string owner, string table)
        {
            return _DbTableExists(owner, table, false, null);
        }
        /// <summary>
        /// Zjistí, zda v připojené databázi existuje daná tabulka.
        /// Vrací true / false, nevyhazuje chyby.
        /// </summary>
        /// <param name="owner">Vlastník tabulky, typicky "lcs"</param>
        /// <param name="table">Název tabulky bez vlastníka, například "sk_sklad"</param>
        /// <param name="direct">true = Přímý test z databáze, obchází cache (Repository.Tables)  /  false = pro testování používá repository</param>
        /// <returns>true = tabulka existuje / false = neexistuje</returns>
        public static bool DbTableExists(string owner, string table, bool direct)
        {
            return _DbTableExists(owner, table, direct, null);
        }
        /// <summary>
        /// Zjistí, zda v připojené databázi existuje daná tabulka.
        /// Vrací true / false, nevyhazuje chyby.
        /// </summary>
        /// <param name="owner">Vlastník tabulky, typicky "lcs"</param>
        /// <param name="table">Název tabulky bez vlastníka, například "sk_sklad"</param>
        /// <param name="connector">Explicitní konektor do databáze. 
        /// Pokud je zadán, a není typu ConnectTypeGreen, pak se vždy obchází repozitory (protože obsah repozitory pochází ze standardní connection).
        /// Pokud je typu ConnectTypeGreen, pak se vždy používá repozitory.
        /// Pokud chceme použít connection do Greenu, a přitom obejít repozitory, je třeba použít variantu se zadáním parametru ( bool direct = true ).
        /// </param>
        /// <returns>true = tabulka existuje / false = neexistuje</returns>
        public static bool DbTableExists(string owner, string table, DataConnector connector)
        {
            bool direct = (connector != null && !connector.IsTypeGreen);
            return _DbTableExists(owner, table, direct, connector);
        }
        /// <summary>
        /// Zjistí, zda v připojené databázi existuje daná tabulka.
        /// Vrací true / false, nevyhazuje chyby.
        /// </summary>
        /// <param name="owner">Vlastník tabulky, typicky "lcs"</param>
        /// <param name="table">Název tabulky bez vlastníka, například "sk_sklad"</param>
        /// <param name="direct">true = Přímý test z databáze, obchází cache (Repository.Tables)  /  false = pro testování používá repository</param>
        /// <param name="connector">Explicitní konektor do databáze. 
        /// Pokud je zadán, a je jiného typu (connector.ConnectType) než DataConnectType.Committed nebo DataConnectType.Uncommitted, 
        /// pak se vždy obchází repozitory (protože obsah repozitory pochází ze standardní connection).</param>
        /// <returns>true = tabulka existuje / false = neexistuje</returns>
        private static bool _DbTableExists(string owner, string table, bool direct, DataConnector connector)
        {
            // Pokud někdo žádá o zjištění informací z Repository, a přitom mi dává explicitní spojení jiné než ConnectTypeGreen, pak nastavíme direct = true = nejdeme do Repository:
            if (!direct && connector != null && !connector.IsTypeGreen)
                direct = true;

            string tableName = owner + "." + table;
            Green.DbTableInfo tableInfo = null;
            bool exists = false;
            if (direct && connector != null)
                exists = Green.Repository.Tables.TryLoadFromDatabase(tableName, connector, out tableInfo);
            else if (direct)
                exists = Green.Repository.Tables.TryLoadFromDatabase(tableName, out tableInfo);
            else
                exists = Green.Repository.Tables.TryGetValue(tableName, out tableInfo);

            return (exists && tableInfo != null);
        }



        /// <summary>
        /// Zjistí, zda v připojené databázi existuje daná tabulka a v ní daný sloupec.
        /// Vrací true / false, nevyhazuje chyby.
        /// </summary>
        /// <param name="owner">Vlastník tabulky, typicky "lcs"</param>
        /// <param name="table">Název tabulky bez vlastníka, například "sk_sklad"</param>
        /// <param name="column">Název sloupce, holý</param>
        /// <returns>true = tabulka existuje / false = neexistuje</returns>
        public static bool DbColumnExists(string owner, string table, string column)
        {
            return _DbColumnExists(owner, table, column, false, null);
        }
        /// <summary>
        /// Zjistí, zda v připojené databázi existuje daná tabulka a v ní daný sloupec.
        /// Vrací true / false, nevyhazuje chyby.
        /// </summary>
        /// <param name="owner">Vlastník tabulky, typicky "lcs"</param>
        /// <param name="table">Název tabulky bez vlastníka, například "sk_sklad"</param>
        /// <param name="column">Název sloupce, holý</param>
        /// <param name="direct">true = Přímý test z databáze, obchází cache (Repository.Tables)  /  false = pro testování používá repository</param>
        /// <returns>true = tabulka existuje / false = neexistuje</returns>
        public static bool DbColumnExists(string owner, string table, string column, bool direct)
        {
            return _DbColumnExists(owner, table, column, direct, null);
        }
        /// <summary>
        /// Zjistí, zda v připojené databázi existuje daná tabulka a v ní daný sloupec.
        /// Vrací true / false, nevyhazuje chyby.
        /// </summary>
        /// <param name="owner">Vlastník tabulky, typicky "lcs"</param>
        /// <param name="table">Název tabulky bez vlastníka, například "sk_sklad"</param>
        /// <param name="column">Název sloupce, holý</param>
        /// <param name="connector">Explicitní konektor do databáze. 
        /// Pokud je zadán, a je jiného typu (connector.ConnectType) než DataConnectType.Committed nebo DataConnectType.Uncommitted, 
        /// pak se vždy obchází repozitory (protože obsah repozitory pochází ze standardní connection).</param>
        /// <returns>true = tabulka existuje / false = neexistuje</returns>
        public static bool DbColumnExists(string owner, string table, string column, DataConnector connector)
        {
            bool direct = (connector != null && !connector.IsTypeGreen);
            return _DbColumnExists(owner, table, column, direct, connector);
        }
        /// <summary>
        /// Zjistí, zda v připojené databázi existuje daná tabulka a v ní daný sloupec.
        /// Vrací true / false, nevyhazuje chyby.
        /// </summary>
        /// <param name="owner">Vlastník tabulky, typicky "lcs"</param>
        /// <param name="table">Název tabulky bez vlastníka, například "sk_sklad"</param>
        /// <param name="column">Název sloupce, holý</param>
        /// <param name="direct">true = Přímý test z databáze, obchází cache (Repository.Tables)  /  false = pro testování používá repository</param>
        /// <param name="connector">Explicitní konektor do databáze. 
        /// Pokud je zadán, a je jiného typu (connector.ConnectType) než DataConnectType.Committed nebo DataConnectType.Uncommitted, 
        /// pak se vždy obchází repozitory (protože obsah repozitory pochází ze standardní connection).</param>
        /// <returns>true = tabulka existuje / false = neexistuje</returns>
        private static bool _DbColumnExists(string owner, string table, string column, bool direct, DataConnector connector)
        {
            // Pokud někdo žádá o zjištění informací z Repository, a přitom mi dává explicitní spojení jiné než ConnectTypeGreen, pak nastavíme direct = true = nejdeme do Repository:
            if (!direct && connector != null && !connector.IsTypeGreen)
                direct = true;

            string tableName = owner + "." + table;
            Green.DbTableInfo tableInfo = null;
            bool exists = false;
            if (direct && connector != null)
                exists = Green.Repository.Tables.TryLoadFromDatabase(tableName, connector, out tableInfo);
            else if (direct)
                exists = Green.Repository.Tables.TryLoadFromDatabase(tableName, out tableInfo);
            else
                exists = Green.Repository.Tables.TryGetValue(tableName, out tableInfo);

            if (!exists || tableInfo == null) return false;

            // Obsahuje seznam sloupců ten hledaný?
            List<Green.DbColumnInfo> columns = tableInfo.ColumnList;
            if (columns == null || columns.Count == 0) return false;

            return (columns.Any(col => String.Equals(col.ColumnName, column, StringComparison.InvariantCultureIgnoreCase)));
        }
        #endregion
        #region Privátní metody: PrimitiveTypes, CreateRecord, FillRecord
        /// <summary>
		/// Které .NET typy jsou natolik primitivní, že je načítáme přímo z DB sloupce?
		/// </summary>
		private static string _PrimitiveTypes;
		/// <summary>
		/// Je daný typ úplně primitivní (tj. odpovídá 1:1 obsahu některého DB sloupce)
		/// </summary>
		/// <param name="type"></param>
		/// <returns></returns>
		private static bool IsPrimitiveType(Type type)
		{
			string name = "," + type.Name + ",";
			if (_PrimitiveTypes == null)
				_PrimitiveTypes = ",Int16,Int32,Int64,DateTime,Decimal,Float,Double,SqlInt16,SqlInt32,SqlInt64,SqlDateTime,SqlDecimal,SqlFloat,SqlDouble,String,";
			return (_PrimitiveTypes.IndexOf(name) >= 0);
		}
		/// <summary>
		/// Z předaného readeru vytvoří a vrátí nový objekt s daty.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		private static T _CreateRecord<T>(SqlDataReader reader, FieldMapperLoad map) where T : new()
		{
			int recordNumber;
			return _CreateRecord<T>(reader, map, out recordNumber);
		}
		/// <summary>
		/// Z předaného readeru vytvoří a vrátí nový objekt s daty.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <param name="recordNumber"></param>
		/// <returns></returns>
		private static T _CreateRecord<T>(SqlDataReader reader, FieldMapperLoad map, out int recordNumber) where T : new()
		{
			T record = new T();
			_FillRecord(record, reader, map, out recordNumber);
			return record;
		}
		/// <summary>
		/// Do předaného objektu vloží data z dodaného readeru za použití mapy.
		/// </summary>
		/// <param name="record"></param>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <param name="recordNumber"></param>
		private static void _FillRecord(object record, SqlDataReader reader, FieldMapperLoad map, out int recordNumber)
		{
			recordNumber = 0;

			IDbFill dbFill = null;
            IDbRecord dbRecord = null;
			bool isFilled = false;

			// Explicitní cesta pro načítání dat do objektů, které implementují interface IDbRecord:
			if (map.IsDbFill)
			{
                dbFill = record as IDbFill;
    			if (dbFill != null)
					isFilled = dbFill.FillFromReader(reader, map);
                if (map.IsDbRecord)
                    dbRecord = record as IDbRecord;
                if (isFilled)
				{	// Objekt si načetl svoje data : můžeme skončit, nepůjdeme generickou cestou:
                    if (dbRecord != null)
                        recordNumber = dbRecord.RecordNumber;
					return;
				}
			}

			// Generická cesta - je implementována v mapperu:
			map.FillDataIntoRecord(reader, record);
			
			// Číslo recordu, konec:
            if (map.IsDbRecord)
                dbRecord = record as IDbRecord;
            if (dbRecord != null)
                recordNumber = dbRecord.RecordNumber;
		}
        /// <summary>
        /// Vrátí data connector požadovaného typu.
        /// Pokud je požadován nepoužitelný typ, vyhodí chybu.
        /// </summary>
        /// <param name="connectType"></param>
        /// <returns></returns>
        private static DataConnector _GetConnector(DataConnectType connectType)
        {
            switch (connectType)
            {
                case DataConnectType.Committed:
                    return DataConnect.ConnectCommitted;
                case DataConnectType.Uncommitted:
                    return DataConnect.ConnectUncommitted;
                case DataConnectType.UserDefined:
                    if (DataConnect.ConnectUserDefined != null)
                        return DataConnect.ConnectUserDefined;
                    Throw.SysError(MessageInfo.Get("Je požadováno použití databázového spojení typu UserDefined, ale toto není připraveno."));
                    break;
                default:
                    Throw.SysError(MessageInfo.Get("Je požadováno použití databázového spojení typu %0, což není přípustné.", connectType));
                    break;
            }
            return null;
        }
        #endregion
		#region Ukládání dat
		/// <summary>
		/// Metoda zajistí uložení dat předaného záznamu do databáze.
		/// </summary>
		/// <param name="record">Záznam k uložení</param>
		public static void SaveRecord(IDbRecord record)
		{
			_SaveUpdate(record, false, null, null);
		}
        /// <summary>
        /// Metoda zajistí uložení dat předaného záznamu do databáze.
        /// </summary>
        /// <param name="record">Záznam k uložení</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void SaveRecord(IDbRecord record, DataConnectType connectType)
        {
            _SaveUpdate(record, false, null, _GetConnector(connectType));
        }
        /// <summary>
		/// Metoda zajistí uložení dat předaného záznamu do databáze.
		/// </summary>
		/// <param name="record">Záznam k uložení</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void SaveRecord(IDbRecord record, DataConnector connector)
		{
			_SaveUpdate(record, false, null, connector);
		}
		/// <summary>
		/// Zajistí update uvedených sloupců předaného záznamu do databáze.
		/// Záznam musí existovat (tj. jeho RecordNumber musí být kladné).
		/// Seznam sloupců může být předán jako pole stringů, nebo jako jeden string s jednotlivými columns oddělenými čárkou.
		/// Pokud tento záznam ukládá data do více tabulek, a je třeba specifikovat jen některou z nich, 
		/// může dbcolumn obsahovat jméno tabulky (například "reference_subjektu, lcs.product_order.nazev_subjektu", atd.)
		/// Seznam se odkazuje na jména sloupců, nikoli jména property nebo fields v objektu. Vyhledání odpovídajících dat je case-insensitive.
		/// Pokud bude v seznamu uveden sloupec, který neexistuje, dojde k chybě.
		/// Pokud bude požadován Update pro záznam, který dosud neexistuje (RecordNumber není kladné), dojde k chybě.
		/// </summary>
		/// <param name="record">Záznam k uložení</param>
		/// <param name="columns">Seznam db columns k update</param>
		public static void UpdateColumns(IDbRecord record, params string[] columns)
		{
			UpdateColumns(record, (DataConnector)null, columns);
		}
        /// <summary>
        /// Zajistí update uvedených sloupců předaného záznamu do databáze.
        /// Záznam musí existovat (tj. jeho RecordNumber musí být kladné).
        /// Seznam sloupců může být předán jako pole stringů, nebo jako jeden string s jednotlivými columns oddělenými čárkou.
        /// Pokud tento záznam ukládá data do více tabulek, a je třeba specifikovat jen některou z nich, 
        /// může dbcolumn obsahovat jméno tabulky (například "reference_subjektu, lcs.product_order.nazev_subjektu", atd.)
        /// Seznam se odkazuje na jména sloupců, nikoli jména property nebo fields v objektu. Vyhledání odpovídajících dat je case-insensitive.
        /// Pokud bude v seznamu uveden sloupec, který neexistuje, dojde k chybě.
        /// Pokud bude požadován Update pro záznam, který dosud neexistuje (RecordNumber není kladné), dojde k chybě.
        /// </summary>
        /// <param name="record">Záznam k uložení</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        /// <param name="columns">Seznam db columns k update</param>
        public static void UpdateColumns(IDbRecord record, DataConnectType connectType, params string[] columns)
        {
            UpdateColumns(record, _GetConnector(connectType), columns);
        }
        /// <summary>
		/// Zajistí update uvedených sloupců předaného záznamu do databáze.
		/// Záznam musí existovat (tj. jeho RecordNumber musí být kladné).
		/// Seznam sloupců může být předán jako pole stringů, nebo jako jeden string s jednotlivými columns oddělenými čárkou.
		/// Pokud tento záznam ukládá data do více tabulek, a je třeba specifikovat jen některou z nich, 
		/// může dbcolumn obsahovat jméno tabulky (například "reference_subjektu, lcs.product_order.nazev_subjektu", atd.)
		/// Seznam se odkazuje na jména sloupců, nikoli jména property nebo fields v objektu. Vyhledání odpovídajících dat je case-insensitive.
		/// Pokud bude v seznamu uveden sloupec, který neexistuje, dojde k chybě.
		/// Pokud bude požadován Update pro záznam, který dosud neexistuje (RecordNumber není kladné), dojde k chybě.
		/// </summary>
		/// <param name="record">Záznam k uložení</param>
		/// <param name="columns">Seznam db columns k update</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void UpdateColumns(IDbRecord record, DataConnector connector, params string[] columns)
		{
			if (record == null)
				Throw.SysError(MessageInfo.Get("Proběhl pokus o uložení dat (UpdateRecord(IDbRecord)), ale je předána instance == null."));

			if (record.RecordNumber <= 0)
				Throw.SysError(MessageInfo.Get("Proběhl pokus o update záznamu %0 třídy %1, záznam ale dosud není uložen v databázi. UDPATE je vyloučen.", record.RecordNumber, record.GetType().ToString()));

			if (columns == null || columns.Length == 0)
				Throw.SysError(MessageInfo.Get("Proběhl pokus o update záznamu %0 třídy %1, nejsou ale předány sloupce k provedení UDPATE.", record.RecordNumber, record.GetType().ToString()));

			List<string> columnList = new List<string>();
			foreach (string columnDef in columns)
			{	// a) na vstupu může být více položek:
				// b) každá položka může obsahovat jednotlivé db columns oddělené čárkou (anebo středníkem):
				string[] cols = columnDef.Split(',', ';');
				foreach (string col in cols)
					columnList.Add(col.Trim());
			}

			_SaveUpdate(record, true, columnList, connector);
		}
		/// <summary>
		/// Metoda, která zajistí ukládání dat (INSERT / UPDATE).
		/// </summary>
		/// <param name="record">Záznam k uložení</param>
		/// <param name="onlyUpdate">Požadavek na režim UPDATE VYBRANÝCH SLOUPCŮ</param>
		/// <param name="columnList">Soupis db sloupců k UDPATE</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		private static void _SaveUpdate(IDbRecord record, bool onlyUpdate, List<string> columnList, DataConnector connector)
		{
			if (record == null)
				Throw.SysError(MessageInfo.Get("Proběhl pokus o uložení dat (SaveRecord(IDbRecord)), ale je předána instance == null."));

			FieldMapperSave map = new FieldMapperSave();
			bool prepared = record.PrepareSaveData(map);
			if (!prepared)
				Throw.SysError(MessageInfo.Get("Proběhl pokus o uložení dat třídy %0, která neumí připravit data k uložení (metoda PrepareSaveData() vrací false).", record.GetType().ToString()));

			if (!map.Valid)
				Throw.SysError(MessageInfo.Get("Proběhl pokus o uložení dat třídy %0, která ale nepřipravila korektní data k uložení (mapa dat z metody PrepareSaveData() není validní).", record.GetType().ToString()));

			// Pokud není zadán explicitní konektor na data, použije se výchozí.
			if (connector == null) connector = DataConnect.CurrentConnect;

			// Ukládání do všech zúčastněných tabulek:
			int recordNumber = record.RecordNumber;
			_SqlCommandType commandType = (recordNumber > 0 ? _SqlCommandType.Update : _SqlCommandType.InsertMaster);
			if (onlyUpdate && commandType != _SqlCommandType.Update)
				Throw.SysError(MessageInfo.Get("Proběhl pokus o update záznamu %0 třídy %1, záznam ale dosud není uložen v databázi. UDPATE je vyloučen.", record.RecordNumber, record.GetType().ToString()));

			string sql = null;
			object result;
			List<FieldMapperOneTableCls> tableDataList = map.TableDataList;
			try
			{
				foreach (FieldMapperOneTableCls tableData in tableDataList)
				{
					switch (commandType)
					{
						case _SqlCommandType.InsertMaster:
							// Insert do master tabulky, ta by měla vygenerovat primary key:
							sql = tableData.GetCommandInsertMaster();
                            using (var scope = Steward.TraceScopeBegin("Db_Layer", "ExecuteScalar", "SQL", connector.ConnectType.ToString(), sql))
                            using (DataCommand command = connector.CreateCommand(sql, 30))
							{
								result = command.ExecuteScalar();          // Provede INSERT a SELECT IDENTITY (as int)
							}
							if (result is int)
							{
								recordNumber = (int)result;                // Nově přidělené číslo záznamu, použije se pro InsertSlave
								record.RecordNumber = recordNumber;        // Vložit do datového objektu
							}
							commandType = _SqlCommandType.InsertSlave;     // Případné další tabulky se budou ukládat v režimu INSERT SLAVE
							break;
						case _SqlCommandType.InsertSlave:
							sql = tableData.GetCommandInsertSlave(recordNumber);
                            using (var scope = Steward.TraceScopeBegin("Db_Layer", "ExecuteNonQuery", "SQL", connector.ConnectType.ToString(), sql))
                            using (DataCommand command = connector.CreateCommand(sql, 30))
                            {
								command.ExecuteNonQuery();                 // INSERT včetně insertu IdentityColumn
							}
							break;
						case _SqlCommandType.Update:
							sql = tableData.GetCommandUpdate(recordNumber, onlyUpdate, columnList);
							if (sql != String.Empty)
							{	// Pokud je něco k provedení UPDATE: 
								//   (ono to nemusí být, protože pokud si aplikace přeje updatovat data jen do jedné tabulky 
								//    a toto není ona, pak se vrátí String.Empty)
                                using (var scope = Steward.TraceScopeBegin("Db_Layer", "ExecuteScalar", "SQL", connector.ConnectType.ToString(), sql))
                                using (DataCommand command = connector.CreateCommand(sql, 30))
                                {
									result = command.ExecuteScalar();      // Provede INSERT a SELECT @@ROWCOUNT AS rows_updated
								}
								if (result is int)
								{
									int rowsUpdated = (int)result;         // Počet vět, které byly updatovány
									if (rowsUpdated == 0)
										Throw.SysError(MessageInfo.Get("Chyba při ukládání záznamu %0 do tabulky %1. Záznam nelze uložit, po načtení z databáze byl smazán.", record.RecordNumber, tableData.TableName));
									else if (rowsUpdated > 1)
										Throw.SysError(MessageInfo.Get("Chyba při ukládání záznamu %0 do tabulky %1. Ukládání záznamu ovlivnilo více než jednu větu tabulky %0 (počet = %1).", tableData.TableName, rowsUpdated));
								}
							}
							break;
					}
				}
			}
			catch (SqlException exc)
			{
				Throw.SqlError(MessageInfo.Get("Došlo k chybě při ukládání dat. Režim ukládání = %0, SQL příkaz = %1.", commandType, sql), exc);
			}
		}
		enum _SqlCommandType { InsertMaster = 1, InsertSlave, Update  }
		#endregion
		#region ExecuteNonQuery
		/// <summary>
		/// Vykoná daný SQL příkaz.
		/// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
		/// </summary>
		/// <param name="sqlCmd">SQL příkaz</param>
		public static void ExecuteNonQuery(string sqlCmd)
		{
			_ExecuteNonQuery(sqlCmd, null, 0, null);
		}
		/// <summary>
		/// Vykoná daný SQL příkaz
		/// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
		/// </summary>
		/// <param name="sqlCmd">SQL příkaz</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		public static void ExecuteNonQuery(string sqlCmd, int timeOut)
		{
			_ExecuteNonQuery(sqlCmd, null, timeOut, null);
		}
        /// <summary>
        /// Vykoná daný SQL příkaz.
        /// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        public static void ExecuteNonQuery(string sqlCmd, SqlParameterCollection parameters)
        {
            _ExecuteNonQuery(sqlCmd, parameters, 0, null);
        }
        /// <summary>
        /// Vykoná daný SQL příkaz
        /// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        public static void ExecuteNonQuery(string sqlCmd, SqlParameterCollection parameters, int timeOut)
        {
            _ExecuteNonQuery(sqlCmd, parameters, timeOut, null);
        }
        /// <summary>
        /// Vykoná daný SQL příkaz.
        /// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void ExecuteNonQuery(string sqlCmd, DataConnectType connectType)
        {
            _ExecuteNonQuery(sqlCmd, null, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Vykoná daný SQL příkaz
        /// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void ExecuteNonQuery(string sqlCmd, int timeOut, DataConnectType connectType)
        {
            _ExecuteNonQuery(sqlCmd, null, timeOut, _GetConnector(connectType));
        }
        /// <summary>
        /// Vykoná daný SQL příkaz.
        /// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void ExecuteNonQuery(string sqlCmd, SqlParameterCollection parameters, DataConnectType connectType)
        {
            _ExecuteNonQuery(sqlCmd, parameters, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Vykoná daný SQL příkaz
        /// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void ExecuteNonQuery(string sqlCmd, SqlParameterCollection parameters, int timeOut, DataConnectType connectType)
        {
            _ExecuteNonQuery(sqlCmd, parameters, timeOut, _GetConnector(connectType));
        }
        /// <summary>
		/// Vykoná daný SQL příkaz.
		/// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
		/// </summary>
		/// <param name="sqlCmd">SQL příkaz</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void ExecuteNonQuery(string sqlCmd, DataConnector connector)
		{
			_ExecuteNonQuery(sqlCmd, null, 0, connector);
		}
		/// <summary>
		/// Vykoná daný SQL příkaz
		/// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
		/// </summary>
		/// <param name="sqlCmd">SQL příkaz</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void ExecuteNonQuery(string sqlCmd, int timeOut, DataConnector connector)
		{
			_ExecuteNonQuery(sqlCmd, null, timeOut, connector);
		}
		/// <summary>
		/// Vykoná daný SQL příkaz.
		/// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
		/// </summary>
		/// <param name="sqlCmd">SQL příkaz</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void ExecuteNonQuery(string sqlCmd, SqlParameterCollection parameters, DataConnector connector)
		{
			_ExecuteNonQuery(sqlCmd, parameters, 0, connector);
		}
		/// <summary>
		/// Vykoná daný SQL příkaz
		/// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
		/// </summary>
		/// <param name="sqlCmd">SQL příkaz</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		public static void ExecuteNonQuery(string sqlCmd, SqlParameterCollection parameters, int timeOut, DataConnector connector)
		{
			_ExecuteNonQuery(sqlCmd, parameters, timeOut, connector);
		}
		/// <summary>
		/// Vykoná daný SQL příkaz
		/// Je zde jen pro pohodlí při psaní kódu, výkonný kód je v DataConnect.ExecuteNonQuery().
		/// </summary>
		/// <param name="sqlCmd">SQL příkaz</param>
		/// <param name="parameters">Sada parametrů. Může být null.</param>
		/// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
		/// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
		private static void _ExecuteNonQuery(string sqlCmd, SqlParameterCollection parameters, int timeOut, DataConnector connector)
		{
			// Pokud není zadán explicitní konektor na data, použije se výchozí.
			if (connector == null) connector = DataConnect.CurrentConnect;

            using (var scope = Steward.TraceScopeBegin("Db_Layer", "ExecuteNonQuery", "SQL", connector.ConnectType.ToString(), sqlCmd))
            {
                try
                {
                    using (DataCommand command = connector.CreateCommand(sqlCmd, parameters, timeOut))
                    {
                        command.ExecuteNonQuery();
                    }
                }
                catch (SqlException exc)
                {
                    throw new SqdException(exc.Message + Environment.NewLine + sqlCmd, exc);
                }
            }
		}
		#endregion
        #region ExecuteNonQueryPart
        /// <summary>
        /// Vykoná daný SQL příkaz.
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        public static void ExecuteNonQueryPart(string sqlCmd)
        {
            _ExecuteNonQueryPart(sqlCmd, null, 0, null);
        }
        /// <summary>
        /// Vykoná daný SQL příkaz
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        public static void ExecuteNonQueryPart(string sqlCmd, int timeOut)
        {
            _ExecuteNonQueryPart(sqlCmd, null, timeOut, null);
        }
        /// <summary>
        /// Vykoná daný SQL příkaz.
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        public static void ExecuteNonQueryPart(string sqlCmd, SqlParameterCollection parameters)
        {
            _ExecuteNonQueryPart(sqlCmd, parameters, 0, null);
        }
        /// <summary>
        /// Vykoná daný SQL příkaz
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        public static void ExecuteNonQueryPart(string sqlCmd, SqlParameterCollection parameters, int timeOut)
        {
            _ExecuteNonQueryPart(sqlCmd, parameters, timeOut, null);
        }
        /// <summary>
        /// Vykoná daný SQL příkaz.
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void ExecuteNonQueryPart(string sqlCmd, DataConnectType connectType)
        {
            _ExecuteNonQueryPart(sqlCmd, null, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Vykoná daný SQL příkaz
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void ExecuteNonQueryPart(string sqlCmd, int timeOut, DataConnectType connectType)
        {
            _ExecuteNonQueryPart(sqlCmd, null, timeOut, _GetConnector(connectType));
        }
        /// <summary>
        /// Vykoná daný SQL příkaz.
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void ExecuteNonQueryPart(string sqlCmd, SqlParameterCollection parameters, DataConnectType connectType)
        {
            _ExecuteNonQueryPart(sqlCmd, parameters, 0, _GetConnector(connectType));
        }
        /// <summary>
        /// Vykoná daný SQL příkaz
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connectType">Typ spojení. Povolené typy jsou Committed, Uncommitted a UserDefined (poslední jen pokud je v dané chvíli dostupno: DataConnect.UserConnectIsPrepared je true)</param>
        public static void ExecuteNonQueryPart(string sqlCmd, SqlParameterCollection parameters, int timeOut, DataConnectType connectType)
        {
            _ExecuteNonQueryPart(sqlCmd, parameters, timeOut, _GetConnector(connectType));
        }
        /// <summary>
        /// Vykoná daný SQL příkaz.
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
        public static void ExecuteNonQueryPart(string sqlCmd, DataConnector connector)
        {
            _ExecuteNonQueryPart(sqlCmd, null, 0, connector);
        }
        /// <summary>
        /// Vykoná daný SQL příkaz
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
        public static void ExecuteNonQueryPart(string sqlCmd, int timeOut, DataConnector connector)
        {
            _ExecuteNonQueryPart(sqlCmd, null, timeOut, connector);
        }
        /// <summary>
        /// Vykoná daný SQL příkaz.
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
        public static void ExecuteNonQueryPart(string sqlCmd, SqlParameterCollection parameters, DataConnector connector)
        {
            _ExecuteNonQueryPart(sqlCmd, parameters, 0, connector);
        }
        /// <summary>
        /// Vykoná daný SQL příkaz
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
        public static void ExecuteNonQueryPart(string sqlCmd, SqlParameterCollection parameters, int timeOut, DataConnector connector)
        {
            _ExecuteNonQueryPart(sqlCmd, parameters, timeOut, connector);
        }
        /// <summary>
        /// Vykoná daný SQL příkaz
        /// Příkaz rozdělí v místech komentářů -- Part: a -- Final:, jednotlivé části vykoná podle zadání.
        /// </summary>
        /// <param name="sqlCmd">SQL příkaz</param>
        /// <param name="parameters">Sada parametrů. Může být null.</param>
        /// <param name="timeOut">TimeOut. Pokud není zadán (nebo není kladný), převezme se timeout z connection (tam je typicky 15 minut).</param>
        /// <param name="connector">DataConnector na explicitní data. Pokud je null, použije se výchozí.</param>
        private static void _ExecuteNonQueryPart(string sqlCmd, SqlParameterCollection parameters, int timeOut, DataConnector connector)
        {
            // Pokud není zadán explicitní konektor na data, použije se výchozí.
            if (connector == null) connector = DataConnect.CurrentConnect;

            string connectType = connector.ConnectType.ToString();
            using (var scope = Steward.TraceScopeBegin("Db_Layer", "ExecuteNonQueryPart", "SQL", connectType, sqlCmd))
            {
                try
                {
                    List<string> sqlCmdParts;
                    string sqlCmdFinal;
                    _ExecuteNonQueryPartSplit(sqlCmd, out sqlCmdParts, out sqlCmdFinal);
                    try
                    {
                        foreach (string sqlCmdPart in sqlCmdParts)
                        {   // Každá jednotlivá část Part:
                            using (var scopeIn = Steward.TraceScopeBegin("Db_Layer", "ExecuteNonQuery", "SQL", connectType, sqlCmdPart))
                            using (DataCommand command = connector.CreateCommand(sqlCmdPart, parameters, timeOut))
                            {
                                command.ExecuteNonQuery();
                            }
                        }
                    }
                    finally
                    {
                        if (!String.IsNullOrEmpty(sqlCmdFinal))
                        {   // Závěrečný Final:
                            using (var scopeIn = Steward.TraceScopeBegin("Db_Layer", "ExecuteNonQuery", "SQL", connectType, sqlCmdFinal))
                            using (DataCommand command = connector.CreateCommand(sqlCmdFinal, parameters, timeOut))
                            {
                                command.ExecuteNonQuery();
                            }
                        }
                    }
                }
                catch (SqlException exc)
                {
                    throw new SqdException(exc.Message + Environment.NewLine + sqlCmd, exc);
                }
            }
        }
        /// <summary>
        /// Rozdělí daný text na jednotlivé části před a po SQL_PART_FINAL, části před tím rozdělí v místě SQL_PART_ITEM.
        /// </summary>
        /// <param name="sqlCmd"></param>
        /// <param name="sqlCmdParts"></param>
        /// <param name="sqlCmdFinal"></param>
        private static void _ExecuteNonQueryPartSplit(string sqlCmd, out List<string> sqlCmdParts, out string sqlCmdFinal)
        {
            sqlCmdParts = new List<string>();
            sqlCmdFinal = null;
            if (String.IsNullOrEmpty(sqlCmd)) return;

            string[] items = sqlCmd.Split(new string[] { SQL_PART_FINAL }, StringSplitOptions.RemoveEmptyEntries);
            int length = items.Length;
            if (length == 0) return;
            if (length > 2)
                Throw.SysError(MessageInfo.Get("Db_Layer.ExecuteNonQueryPart(): command contain too many FINAL parts (%0).", (length - 1)));
            if (length == 2)
                sqlCmdFinal = items[1];

            sqlCmdParts = items[0].Split(new string[] { SQL_PART_ITEM }, StringSplitOptions.RemoveEmptyEntries).ToList();
        }
        /// <summary>
        /// Konstanta, která odděluje jednotlivé části děleného SQL příkazu (části které se spouštějí jako oddělené dávky).
        /// Pokud v některé části dojde k chybě, další části se už nezpracují. Ale zpracuje se část za SQL_PART_FINAL.
        /// </summary>
        public const string SQL_PART_ITEM = "-- Part:";
        /// <summary>
        /// Konstanta, která zahajuje část FINAL děleného SQL příkazu (text následující za touto konstntou se spustí i po chybě, ke které by došlo v příkazech SQL_PART_ITEM)
        /// </summary>
        public const string SQL_PART_FINAL = "-- Final:";
        #endregion
    }
	#endregion
	#region DbTempTableDisposable : objekt IDIsposable, který při svém Dispose zajistí DROP pro Temp tabulku uloženou v tomto objektu.
    /// <summary>
    /// DbTempTableDisposable : objekt IDIsposable, který při svém Dispose zajistí DROP pro Temp tabulku uloženou v tomto objektu.
    /// </summary>
    public class DbTempTableDisposable : IDisposable
    {
        internal DbTempTableDisposable(string tableName, DataConnector connector)
        {
            this.TableName = tableName;
            this.Connector = connector;
        }
        /// <summary>
        /// Název TEMP tabulky v tomto objektu uložené, která bude při Dispose objektu ukončená.
        /// </summary>
        public string TableName { get; private set; }
        private DataConnector Connector { get; set; }
        public static implicit operator string(DbTempTableDisposable table) { return table.TableName; }
        void IDisposable.Dispose()
        {
            Db_Layer.TempTableDrop(this.TableName, this.Connector);
        }
    }
	#endregion
	#region CLASS FieldMapperLoad : mapa sloupců pro načítání dat z databáze do strukturovaného záznamu
	/// <summary>
	/// FieldMapperLoad : mapa sloupců pro načítání dat z databáze do strukturovaného záznamu
	/// </summary>
	public class FieldMapperLoad
	{
		#region KONSTRUKCE
		internal FieldMapperLoad()
		{
			_Map = new Dictionary<string, ColumnFieldLinkCls>();
		}
		private Dictionary<string, ColumnFieldLinkCls> _Map;
		/// <summary>
		/// Navázaný objekt implementuje IDbFill
		/// </summary>
        public bool IsDbFill { get; private set; }
        /// <summary>
        /// Navázaný objekt implementuje IDbRecord
        /// </summary>
        public bool IsDbRecord { get; private set; }
		#endregion
		#region TVORBA MAPY
		/// <summary>
		/// Vygeneruje mapu, která propojuje data ze vstupního readeru na odpovídající field struktury T
		/// </summary>
		/// <param name="typeRec">Typ záznamu</param>
		/// <param name="reader">DataReader</param>
		/// <param name="isDbFill">Je to IDbRecord?</param>
		/// <returns>Mapa DbColumns = Fields</returns>
        private void _FillMapper(Type typeRec, SqlDataReader reader, bool isDbFill, bool isDbRecord)
		{
			_Map = new Dictionary<string, ColumnFieldLinkCls>();
			this.IsDbFill = isDbFill;
            this.IsDbRecord = isDbRecord;

			List<FieldInfo> fields = new List<FieldInfo>(typeRec.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance));      // Type => Fields[] => List
			for (int c = 0; c < reader.FieldCount; c++)
			{
				string columnName = reader.GetName(c).ToLower();    // Jméno sloupce převedu na Lower
				if (_Map.ContainsKey(columnName)) continue;         // Někdy (u blbých selectů) může být víc columnů se shodným názvem, ale tady duplicitní data nechceme.

				string fieldName = "_" + columnName;
				FieldInfo field = fields.Find(delegate(FieldInfo scanField) { return (scanField.Name == fieldName); });
				if (field == null) continue;                        // Žádný field se nejmenuje tak, aby byl vhodně propojen s columnem ze selectu

				// TypeConversion:
				string dbType = reader.GetDataTypeName(c);
				string dotNetType = field.FieldType.Name;           // Např. "Int32", "SqlInt32", atd
				DbToNetConvType typeConversion = _GetDbToNetConvType(dotNetType, dbType);

				_Map.Add(columnName, new ColumnFieldLinkCls(c, field, typeConversion));
			}
		}
		/// <summary>
		/// Vrátí typ konverze z DB type na DotNET typ.
		/// </summary>
		/// <param name="dotNetType"></param>
		/// <param name="dbType"></param>
		/// <returns></returns>
		private static DbToNetConvType _GetDbToNetConvType(string dotNetType, string dbType)
		{
			// Nejprve vyřeším netypické případy (bool to int, int to bool, string to bool, atd):
			string types = dbType + ":" + dotNetType;
			switch (types)
			{	// "Vstupní:Výstupní datový typ" => určení metody, kterou budeme data načítat z readeru:
				case "bit:Boolean":
					return DbToNetConvType.Bool;
				case "bit:Int16":
					return DbToNetConvType.BoolInt16;
				case "bit:Int32":
					return DbToNetConvType.BoolInt32;
				case "smallint:Int32":
                    return DbToNetConvType.SmallintInt32;
				case "tinyint:Byte":
					return DbToNetConvType.TinyByte;
				case "tinyint:Int16":
					return DbToNetConvType.TinyInt16;
				case "tinyint:Int32":
					return DbToNetConvType.TinyInt32;
			}

			// Standardní konverze běží z jakéhokoli DB typu na konkrétní .NET Type:
			switch (dotNetType)
			{
				case "Int16":
					return DbToNetConvType.Int16;
				case "Int32":
					return DbToNetConvType.Int32;
				case "Int64":
					return DbToNetConvType.Int64;
				case "Decimal":
					return DbToNetConvType.Decimal;
				case "Double":
					return DbToNetConvType.Double;
				case "Float":
					return DbToNetConvType.Float;
				case "DateTime":
					return DbToNetConvType.DateTime;

				case "SqlInt16":
					return DbToNetConvType.SqlInt16;
				case "SqlInt32":
					return DbToNetConvType.SqlInt32;
				case "SqlInt64":
					return DbToNetConvType.SqlInt64;
				case "SqlDecimal":
					return DbToNetConvType.SqlDecimal;
				case "SqlDouble":
					return DbToNetConvType.SqlDouble;
				case "SqlDateTime":
					return DbToNetConvType.SqlDateTime;

				case "String":
					return DbToNetConvType.String;
				case "Char":
					return DbToNetConvType.Char;
			}

			return DbToNetConvType.Implicit;
		}
		#endregion
		#region ČTENÍ DAT S POUŽITÍM MAPY
		/// <summary>
		/// Naplní data z readeru do daného objektu pomocí generické metody FieldInfo.SetValue.
		/// Tato technika je vhodná pro menší množství dat, je cca 8x pomalejší než explicitní plnění dat (typicky this._field = value;).
		/// Pro explicitní techniku je třeba použít metodu (FieldMapperLoad).FillDataIntoField()
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="reader"></param>
		/// <param name="record"></param>
		internal void FillDataIntoRecord<T>(SqlDataReader reader, T record) where T : new()
		{
			foreach (ColumnFieldLinkCls link in _Map.Values)
			{
				int i = link.ColumnIndex;
				bool isNull = reader.IsDBNull(i);

				bool valuePresent;
				try
				{
					object value = _ReadColumnValue(link, reader, out valuePresent);
					if (valuePresent)
						link.FieldInfo.SetValue(record, value);
				}
				catch (Exception exc)
				{
					int colIdx = link.ColumnIndex;
					string value = "";
					string type = "";
					if (reader.IsDBNull(colIdx))
						value = "DbNull";
					else
					{
						object data = reader.GetValue(colIdx);
						value = data.ToString();
						type = " [" + value.GetType().ToString() + "]"; 
					}
					throw new InvalidCastException("Invalid cast on " + record.GetType().ToString() + "." + link.FieldInfo.Name + ", convert = " + link.TypeConversion.ToString() + ", value = " + value + type, exc);
				}
			}			
		}
		/// <summary>
		/// Z readeru načte data a vrátí je v přiměřeném typu.
		/// Vyhledá DB sloupec podle daného názvu.
		/// Pokud sloupec nenajde, vrátí default daného typu.
		/// </summary>
		/// <param name="columnName"></param>
		/// <param name="reader"></param>
		/// <returns></returns>
		public object FillDataIntoField<F>(string columnName, SqlDataReader reader)
		{
			F result = default(F);

			ColumnFieldLinkCls link;
			if (_Map.TryGetValue(columnName, out link))
			{
				bool valuePresent;
				object value = _ReadColumnValue(link, reader, out valuePresent);
				if (valuePresent)
					return value;
			}
			
			return result;
		}
		/// <summary>
		/// Zde se provede čtení hodnoty z DataReaderu ze sloupce specifikovaného popiskem sloupce (ColumnFieldLinkCls link).
		/// </summary>
		/// <param name="link"></param>
		/// <param name="reader"></param>
		/// <param name="valuePresent"></param>
		/// <returns></returns>
		private object _ReadColumnValue(ColumnFieldLinkCls link, SqlDataReader reader, out bool valuePresent)
		{
			valuePresent = true;
			int i = link.ColumnIndex;
			bool isNull = reader.IsDBNull(i);

            try
            {
                switch (link.TypeConversion)
                {
                    // Základní:
                    case DbToNetConvType.Bool:
                        return reader.GetBoolean(i);
                    case DbToNetConvType.BoolInt16:
                        return (Int16)(reader.GetBoolean(i) ? (Int16)1 : (Int16)0);
                    case DbToNetConvType.BoolInt32:
                        return (Int32)(reader.GetBoolean(i) ? (Int32)1 : (Int32)0);
                    case DbToNetConvType.SmallintInt32:
                        return (Int32)reader.GetInt16(i);
                    case DbToNetConvType.TinyByte:
                        return (Byte)reader.GetByte(i);
                    case DbToNetConvType.TinyInt16:
                        return (Int16)reader.GetByte(i);
                    case DbToNetConvType.TinyInt32:
                        return (Int32)reader.GetByte(i);
                    case DbToNetConvType.Int16:
                        return (Int16)reader.GetInt16(i);
                    case DbToNetConvType.Int32:
                        return (Int32)reader.GetInt32(i);
                    case DbToNetConvType.Int64:
                        return (Int64)reader.GetInt64(i);
                    case DbToNetConvType.Decimal:
                        return (decimal)reader.GetDecimal(i);
                    case DbToNetConvType.Double:
                        return (double)reader.GetDouble(i);
                    case DbToNetConvType.Float:
                        return (float)reader.GetFloat(i);
                    case DbToNetConvType.DateTime:
                        return (DateTime)reader.GetDateTime(i);

                    // SqlNull:
                    case DbToNetConvType.SqlInt16:
                        if (!isNull)
                            return (SqlInt16)reader.GetInt16(i);
                        valuePresent = false;
                        return SqlInt16.Null;
                    case DbToNetConvType.SqlInt32:
                        if (!isNull)
                            return (SqlInt32)reader.GetInt32(i);
                        valuePresent = false;
                        return SqlInt32.Null;
                    case DbToNetConvType.SqlInt64:
                        if (!isNull)
                            return (SqlInt64)reader.GetInt64(i);
                        valuePresent = false;
                        return SqlInt64.Null;
                    case DbToNetConvType.SqlDecimal:
                        if (!isNull)
                            return (SqlDecimal)reader.GetDecimal(i);
                        valuePresent = false;
                        return SqlDecimal.Null;
                    case DbToNetConvType.SqlDouble:
                        if (!isNull)
                            return (SqlDouble)reader.GetDouble(i);
                        valuePresent = false;
                        return SqlDouble.Null;
                    case DbToNetConvType.SqlDateTime:
                        if (!isNull)
                            return (SqlDateTime)reader.GetDateTime(i);
                        valuePresent = false;
                        return SqlDateTime.Null;

                    // Char, String
                    case DbToNetConvType.Char:
                        if (!isNull)
                            return (char)reader.GetChar(i);
                        valuePresent = false;
                        return '\0';
                    case DbToNetConvType.String:
                        if (!isNull)
                            return (string)reader.GetString(i);
                        valuePresent = false;
                        return null;
                    default:
                        if (!isNull)
                            return reader.GetValue(i);
                        valuePresent = false;
                        return null;
                }
            }
            catch (Exception exc)
            {
                string msg =
                    "Wrong type conversion for member: " + link.FieldInfo.ReflectedType.Name + "." + link.FieldInfo.Name +
                    "; SQL reader: column name=" + reader.GetName(link.ColumnIndex) + "; index=" + link.ColumnIndex.ToString() + "; DataType=" + reader.GetDataTypeName(link.ColumnIndex) +
                    "; Conversion type: " + link.TypeConversion.ToString();

                Steward.Audit(AuditRowType.CoreError, msg, exc);
                throw new SqdException(msg, exc);
            }
		}
		#endregion
		#region SUBCLASS ColumnFieldLinkCls (položky mapy), ENUM DbToNetConvType (datové konverze typů)
		/// <summary>
		/// Privátní struktura vztahu mezi DbColumnem a Fields generického typu, včetně typu konverze.
		/// </summary>
		protected class ColumnFieldLinkCls
		{
			/// <summary>
			/// Konstruktor
			/// </summary>
			/// <param name="columnIndex"></param>
			/// <param name="fieldInfo"></param>
			/// <param name="typeConversion"></param>
			public ColumnFieldLinkCls(int columnIndex, FieldInfo fieldInfo, DbToNetConvType typeConversion)
			{
				ColumnIndex = columnIndex;
				FieldInfo = fieldInfo;
				TypeConversion = typeConversion;
			}
			/// <summary>
			/// Ordinal index sloupce z DataReaderu
			/// </summary>
			public int ColumnIndex;
			/// <summary>
			/// FieldInfo, do něhož se ukládají data z tohoto sloupce
			/// </summary>
			public FieldInfo FieldInfo;
			/// <summary>
			/// Informace o datové konverzi = metoda, kterou budeme načítat data z DataReaderu
			/// </summary>
			public DbToNetConvType TypeConversion;
			/// <summary>
			/// Vizualizace
			/// </summary>
			/// <returns></returns>
			public override string ToString()
			{
				return "{Link: column [" + ColumnIndex.ToString() + "] => field T." + FieldInfo.Name + " (" + this.TypeConversion.ToString() + ")}";
			}
		}
		/// <summary>
		/// Enum, určuje druh konverze z DB do .NET
		/// </summary>
		protected enum DbToNetConvType
		{
#pragma warning disable 1591
			NotExists = 1,
			Implicit,
			Int16,
			Int32,
			Int64,
			SqlInt16,
			SqlInt32,
			SqlInt64,
			Decimal,
			Double,
			Float,
			SqlDecimal,
			SqlDouble,
			Bool,
			BoolInt16,
			BoolInt32,
            SmallintInt32,
			TinyByte,
			TinyInt16,
			TinyInt32,
			DateTime,
			SqlDateTime,
			Char,
			String
#pragma warning restore 1591
		}
		#endregion
		#region STATICKÝ KONSTRUKTOR GetMap : vrací připravenou mapu
		/// <summary>
		/// Sestaví a vrátí mapu vztahů mezi proměnnými dané třídy a právě načítanými daty
		/// </summary>
		/// <param name="typeRec"></param>
		/// <param name="reader"></param>
		/// <returns></returns>
		internal static FieldMapperLoad GetMap(Type typeRec, SqlDataReader reader)
		{
            // Určím, zda typ (typeRec) implementuje rozhraní IDbFill:
			bool isDbFill = Steward.TestTypeImplementInterface(typeRec, typeof(IDbFill));
            bool isDbRecord = Steward.TestTypeImplementInterface(typeRec, typeof(IDbRecord));
			FieldMapperLoad map = new FieldMapperLoad();
            map._FillMapper(typeRec, reader, isDbFill, isDbRecord);
			return map;
		}
		#endregion
	}
	#endregion
	#region CLASS FieldMapperSave : mapa sloupců a dat pro ukládání dat ze strukturovaného záznamu do databáze
	/// <summary>
	/// FieldMapperSave : mapa sloupců a dat pro ukládání dat ze strukturovaného záznamu do databáze.
	/// Řešení, které poskytuje tato třída, umožní ukládat data z jednoho datového objektu do více tabulek, vždy do jednoho záznamu.
	/// 
	/// </summary>
	public class FieldMapperSave
	{
		#region KONSTRUKCE
		internal FieldMapperSave()
		{
			_TableData = new Dictionary<string, FieldMapperOneTableCls>();
			_CurrentTable = null;
		}
		/// <summary>
		/// Seznam jednotlivých tabulek, které se budou ukládat
		/// </summary>
		internal List<FieldMapperOneTableCls> TableDataList { get { return new List<FieldMapperOneTableCls>(_TableData.Values); } }
		private Dictionary<string, FieldMapperOneTableCls> _TableData;
		private FieldMapperOneTableCls _CurrentTable;
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "{FieldMapperSave: TablesCount=" + _TableData.Count.ToString() + "}";
		}
		#endregion
		#region VSTUP DAT Z DATOVÉHO OBJEKTU, Z JEHO METODY PrepareSaveData(map)
		/// <summary>
		/// Vloží do mapy informaci o názvu tabulky a o názvu jejího primary key columnu.
		/// Je povoleno vložit jako jméno tabulky prázdný string, tím se objektu sdělí, že zadávání sloupců jedné tabulky bylo ukončeno.
		/// To je identické chování, jako volání metody AddTableEnd(), více viz tam.
		/// Pokud další metoda chce přidávat data k tabulce, která už byla jednou zadána, je to přípustné.
		/// Hodnotu primary key si DbLayer načte z objektu přes IDbRecord.RecordNumber, 
		/// kteréžto číslo musí být rovno PrimaryKey v tabulce v daném sloupci.
		/// </summary>
		/// <param name="tableName"></param>
		/// <param name="identityColumnName"></param>
		public void AddTable(string tableName, string identityColumnName)
		{
			// Končíme s jednou tabulkou:
			if (String.IsNullOrEmpty(tableName))
			{
				_CurrentTable = null;
				return;
			}

			// Zahájení jedné tabulky - kontrola identityColumnName:
			if (String.IsNullOrEmpty(identityColumnName))
				Throw.SysError(MessageInfo.Get("Nelze zadávat data do tabulky bez určení primárního klíče. Tabulka: %0.", tableName));

			// Najít/vytvořit objekt mapy jedné tabulky:
			string tblName = tableName.Trim().ToLower();
			FieldMapperOneTableCls oneTable;
			if (!_TableData.TryGetValue(tblName, out oneTable))
			{
				oneTable = new FieldMapperOneTableCls(tableName, identityColumnName);
				_TableData.Add(tblName, oneTable);
			}

			// Aktivovat vybranou tabulku:
			_CurrentTable = oneTable;
		}
		/// <summary>
		/// Ukončí zadávání dat sloupců do jedné tabulky.
		/// Případné další vstupy dat sloupců musí být uvozeny jménem nové tabulky.
		/// Například se to používá v metodě, která plní subjektová data do tabulky lcs.subjekty.
		/// Ukončení dat sloupců jedné tabulky zajistí, že data sloupců pro další tabulku musí explicitně začít zadáním jména této tabulky,
		/// a že se nebudou ukládat data sloupců další tabulky omylem do tabulky specifikované v předešlé skupině.
		/// Pokud bude po volání této metody AddTableEnd() vložena hodnota sloupce (metoda AddColumn()) 
		/// bez specifikace tabulky (metoda AddTable()), dojde k chybě.
		/// Pokud další metoda chce přidávat data k tabulce, která už byla jednou zadána, je to přípustné.
		/// </summary>
		public void AddTableEnd()
		{
			_CurrentTable = null;
		}
		/// <summary>
		/// Vloží do mapy informaci o názvu sloupce a obsah jeho dat.
		/// Tato hodnota se do databáze uloží jak při Insertu, tak při Update.
		/// Pokud je třeba zadat hodnotu, která se vloží jen při Insertu, použije se metoda AddColumnForInsert().
		/// </summary>
		/// <param name="columnName">Název dbcolumnu</param>
		/// <param name="value">Hodnota do tohoto columnu</param>
		public void AddColumn(string columnName, object value)
		{
			_AddColumn(FieldMapperOneColumnMode.AnyCase, columnName, value, -1);
		}
		/// <summary>
		/// Vloží do mapy informaci o názvu sloupce a obsah jeho dat.
		/// Tato hodnota se do databáze uloží jak při Insertu, tak při Update.
		/// Pokud je třeba zadat hodnotu, která se vloží jen při Insertu, použije se metoda AddColumnForInsert().
		/// </summary>
		/// <param name="columnName">Název dbcolumnu</param>
		/// <param name="value">Hodnota do tohoto columnu</param>
		/// <param name="maxLength">Maximální délka pro sloupce typu char, varchar (vycházející ze stringu), akceptují se pouze kladné hodnoty. Nula a záporné = bez omezení.</param>
		public void AddColumn(string columnName, object value, int maxLength)
		{
			_AddColumn(FieldMapperOneColumnMode.AnyCase, columnName, value, maxLength);
		}
		/// <summary>
		/// Vloží do mapy informaci o názvu sloupce a obsah jeho dat.
		/// Tato hodnota se do databáze uloží výhradně při variantě Update, ale ne při Insert.
		/// Typicky se touto cestou plní sloupce "modifikováno dne", "modifikoval", atd 
		/// - tedy takové, které se při zakládání záznamu nenastavují, ale je třeba je aktualizovat až při první a každé další modifikaci.
		/// </summary>
		/// <param name="columnName">Název dbcolumnu</param>
		/// <param name="value">Hodnota do tohoto columnu</param>
		public void AddColumnForUpdate(string columnName, object value)
		{
			_AddColumn(FieldMapperOneColumnMode.OnlyUpdate, columnName, value, -1);
		}
		/// <summary>
		/// Vloží do mapy informaci o názvu sloupce a obsah jeho dat.
		/// Tato hodnota se do databáze uloží výhradně při variantě Update, ale ne při Insert.
		/// Typicky se touto cestou plní sloupce "modifikováno dne", "modifikoval", atd 
		/// - tedy takové, které se při zakládání záznamu nenastavují, ale je třeba je aktualizovat až při první a každé další modifikaci.
		/// </summary>
		/// <param name="columnName">Název dbcolumnu</param>
		/// <param name="value">Hodnota do tohoto columnu</param>
		/// <param name="maxLength">Maximální délka pro sloupce typu char, varchar (vycházející ze stringu), akceptují se pouze kladné hodnoty. Nula a záporné = bez omezení.</param>
		public void AddColumnForUpdate(string columnName, object value, int maxLength)
		{
			_AddColumn(FieldMapperOneColumnMode.OnlyUpdate, columnName, value, maxLength);
		}
		/// <summary>
		/// Vloží do mapy informaci o názvu sloupce a obsah jeho dat.
		/// Tato hodnota se do databáze uloží výhradně při variantě Insert, ale ne při Update.
		/// Typicky se touto cestou plní sloupce "založeno dne", "založil", "číslo pořadače", atd 
		/// - tedy takové, které se po založení záznamu již nemění.
		/// </summary>
		/// <param name="columnName">Sloupec</param>
		/// <param name="value">Hodnota do sloupce</param>
		public void AddColumnForInsert(string columnName, object value)
		{
			_AddColumn(FieldMapperOneColumnMode.OnlyInsert, columnName, value, -1);
		}
		/// <summary>
		/// Vloží do mapy informaci o názvu sloupce a obsah jeho dat.
		/// Tato hodnota se do databáze uloží výhradně při variantě Insert, ale ne při Update.
		/// Typicky se touto cestou plní sloupce "založeno dne", "založil", "číslo pořadače", atd 
		/// - tedy takové, které se po založení záznamu již nemění.
		/// </summary>
		/// <param name="columnName">Sloupec</param>
		/// <param name="value">Hodnota do sloupce</param>
		/// <param name="maxLength">Maximální délka pro sloupce typu char, varchar (vycházející ze stringu), akceptují se pouze kladné hodnoty. Nula a záporné = bez omezení.</param>
		public void AddColumnForInsert(string columnName, object value, int maxLength)
		{
			_AddColumn(FieldMapperOneColumnMode.OnlyInsert, columnName, value, maxLength);
		}
		/// <summary>
		/// Do current tabulky přidá další sloupec (režim, název, hodnotu).
		/// </summary>
		/// <param name="columnMode">Režim sloupce</param>
		/// <param name="columnName">Sloupec</param>
		/// <param name="value">Hodnota do sloupce</param>
		/// <param name="maxLength">Maximální délka pro sloupce typu char, varchar (vycházející ze stringu), akceptují se pouze kladné hodnoty. Nula a záporné = bez omezení.</param>
		private void _AddColumn(FieldMapperOneColumnMode columnMode, string columnName, object value, int maxLength)
		{
			if (_CurrentTable == null)
				Throw.SysError(MessageInfo.Get("Nelze přidávat data DbColumn bez předchozího zadání TableName."));
			_CurrentTable.ColumnsData.Add(new FieldMapperOneColumnCls(columnMode, columnName, value, maxLength));
		}
		#endregion
		#region VYHODNOCOVÁNÍ DAT, SESTAVENÍ PODKLADŮ PRO SQL PŘÍKAZY
		/// <summary>
		/// Příznak true, pokud je mapa dat validní.
		/// </summary>
		internal bool Valid { get { return _IsValid(); } }
		private bool _IsValid()
		{
			if (_TableData == null || _TableData.Count == 0) return false;

			foreach (FieldMapperOneTableCls table in _TableData.Values)
			{
				if (!table.Valid)
					return false;
			}
			return true;
		}

		#endregion
	}
	#region CLASS FieldMapperOneTableCls : data jedné tabulky
	/// <summary>
	/// Třída, které v sobě nese data pro ukládání do jedné tabulky
	/// </summary>
	internal class FieldMapperOneTableCls
	{
		#region KONSTRUKCE
		internal FieldMapperOneTableCls(string tableName, string identityColumnName)
		{
			_TableName = tableName;
			_IdentityColumnName = identityColumnName;
			_ColumnsData = new List<FieldMapperOneColumnCls>();
		}
		/// <summary> { get; }
		/// Název tabulky
		/// </summary>
		internal string TableName { get { return _TableName; } }
		private string _TableName;
		/// <summary> { get; }
		/// Název identity sloupce (cislo_subjektu, cislo_nonsubjektu, cislo_objektu)
		/// </summary>
		internal string IdentityColumnName { get { return _IdentityColumnName; } }
		private string _IdentityColumnName;
		/// <summary> { get; }
		/// Název identity sloupce (cislo_subjektu, cislo_nonsubjektu, cislo_objektu)
		/// </summary>
		internal List<FieldMapperOneColumnCls> ColumnsData { get { return _ColumnsData; } }
		private List<FieldMapperOneColumnCls> _ColumnsData;
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "{Table name=" + this.TableName + " (PK=" + this.IdentityColumnName + "); ColumnCount=" + _ColumnsData.Count.ToString() + "}";
		}
		/// <summary>
		/// Příznak true, pokud je mapa dat validní.
		/// </summary>
		internal bool Valid { get { return _IsValid(); } }
		private bool _IsValid()
		{
			// Deklarace jména tabulky a identity columnu:
			if (String.IsNullOrEmpty(this.TableName)) return false;
			if (String.IsNullOrEmpty(this.IdentityColumnName)) return false;

			// Alespoň jedna deklarace sloupce:
			bool containColumnData = _ColumnsData.Exists(delegate(FieldMapperOneColumnCls item)
				{ return (!String.IsNullOrEmpty(item.ColumnName)); });
			if (!containColumnData) return false;

			return true;
		}
		#endregion
		#region GENEROVÁNÍ SQL PŘÍKAZŮ INSERT (Master, Slave), UPDATE
		/// <summary>
		/// Sestaví a vrátí SQL příkaz pro UPDATE záznamu do této tabulky.
		/// Pokud bude sestaven UPDATE bez jediného sloupce k update, vrátí se String.Empty !
		/// Příkaz obsahuje UPDATE (fields) (WHERE primary_key = parametr),
		/// a poté obsahuje SELECT @@ROWCOUNT AS rows_updated,
		/// který musí vrátit int s hodnotu 1 = jedna věta updatovaná.
		/// Pokud vrátí 0, pak se updatovaná věta před provedením update ztratila.
		/// Pokud vrátí více než 1, pak se updatovalo více vět než jedna.
		/// </summary>
		/// <param name="recordNumber"></param>
		/// <param name="onlyUpdate">Požadavek na režim UPDATE VYBRANÝCH SLOUPCŮ</param>
		/// <param name="columnList">Soupis db sloupců k UDPATE</param>
		/// <returns></returns>
		internal string GetCommandUpdate(int recordNumber, bool onlyUpdate, List<string> columnList)
		{
			string newLine = "\r\n";
			string addComma = "";
			string sql = "UPDATE " + this.TableName + " SET ";
			int len = sql.Length;
			string spac = "  ";
			int maxLen = 145;      // Největší přípustná délka řádku v SQL příkazu (řádek ohraničený CrLf) (jednotlivé výrazy samozřejmě nedělím!)
			int columnCount = 0;   // Kolik DbColumns jsme do UPDATE skutečně vložili
			foreach (FieldMapperOneColumnCls column in _ColumnsData)
			{
				if (!(column.ColumnMode == FieldMapperOneColumnMode.AnyCase || column.ColumnMode == FieldMapperOneColumnMode.OnlyUpdate))
					// Tento column nemá nastaven režim AnyCase nebo OnlyUpdate => přeskočím jej, nemá se dávat do UPDATE:
					continue;

				// Určím, zda se daný sloupec má vložit do UPDATE podle požadavky "onlyUpdate" a soupisu požadovaných db columnů:
				bool isInList = (onlyUpdate ? this._IsColumnInRequest(column, columnList) : true);
				if (!isInList) continue;

				string add = column.ColumnName + " = " + column.SqlValue;
				
				bool wrapLine = (len + addComma.Length + add.Length > maxLen);
				if (wrapLine)
				{	// Řádek by byl moc dlouhý: vložíme [čárku], CrLf, mezery:
					sql += addComma + newLine + spac;
					len = spac.Length;
				}
				else
				{	// Řádek nebude tak dlouhý: přidáme jen [čárku]:
					sql += addComma;
					len += addComma.Length;
				}
				columnCount++;
				sql += add;
				len += add.Length;
				if (addComma.Length == 0) addComma = ", ";
			}

			// Žádný sloupec k update? Žádný SQL příkaz:
			if (columnCount == 0) return String.Empty;

			sql += newLine + "WHERE " + this.IdentityColumnName + " = " + SqlFormat.ToSql(recordNumber) + ";" + newLine +
				newLine +
				"SELECT @@ROWCOUNT AS rows_updated";
			return sql;
		}
		/// <summary>
		/// Metoda zjistí, zda daný sloupec se má vložit do UPDATE z pohledu seznamu sloupců.
		/// Na vstupu je aktuální sloupec, který se má/nemá přidat do SQL příkazu,
		/// a je předán seznam DB sloupců, které si aplikace přeje updatovat.
		/// Metoda vrací true = dát column do UPDATE / false = aplikaci si to nepřeje.
		/// </summary>
		/// <param name="column">Aktuální sloupec</param>
		/// <param name="columnList">Seznam požadovaných sloupců, které si aplikace přeje updatovat.</param>
		/// <returns></returns>
		private bool _IsColumnInRequest(FieldMapperOneColumnCls column, List<string> columnList)
		{
			if (columnList == null || columnList.Count == 0) return false;

			string cNameSTC = this.TableName + "." + column.ColumnName;          // Např.: "lcs.product_order.qty"
			string cNameC = column.ColumnName;                                   // Např.: "qty"
			foreach (string columnName in columnList)
			{
				string cName = (columnName.Contains(".") ? cNameSTC : cNameC);   // Pokud je v položce seznamu tečka, porovnáme s plným jménem sloupce, jinak s holým jménem
				if (String.Equals(cName, columnName, StringComparison.OrdinalIgnoreCase))
					return true;
			}
			return false;
		}
		/// <summary>
		/// Sestaví a vrátí SQL příkaz pro INSERT záznamu do master tabulky (první v řadě, tato tabulka generuje primary key).
		/// Součástí příkazu (po dokončení INSERT) je SELECT @@IDENTITY; 
		/// který vrátí int = číslo posledně založeného záznamu = číslo identity nově insertovaného záznamu.
		/// </summary>
		/// <returns></returns>
		internal string GetCommandInsertMaster()
		{
			return _GetCommandInsert(false, 0);
		}
		/// <summary>
		/// Sestaví a vrátí SQL příkaz pro INSERT záznamu do slave tabulky (podřízená od master tabulky, tato tabulka přijímá primary key přidělený v master tabulce).
		/// Tento INSERT nevrací číslo záznamu.
		/// </summary>
		/// <returns></returns>
		internal string GetCommandInsertSlave(int identityValue)
		{
			return _GetCommandInsert(true, identityValue);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="withIdentityColumn"></param>
		/// <param name="identityValue"></param>
		/// <returns></returns>
		private string _GetCommandInsert(bool withIdentityColumn, int identityValue)
		{
			string newLine = "\r\n";
			string addComma = "";
			string sql1 = "INSERT INTO " + this.TableName + " (";
			string sql2 = "     VALUES (";

			// SLAVE tabulka: provedeme INSERT hodnoty do identity columnu:
			if (withIdentityColumn)
			{
				sql1 += this.IdentityColumnName;
				sql2 += SqlFormat.ToSql(identityValue);
				addComma = ", ";
			}

			int len1 = sql1.Length;
			int len2 = sql2.Length;
			string spac = "             ";
			int maxLen = 145;      // Největší přípustná délka řádku v SQL příkazu (řádek ohraničený CrLf) (jednotlivé výrazy samozřejmě nedělím!)
			foreach (FieldMapperOneColumnCls column in _ColumnsData)
			{
				if (!(column.ColumnMode == FieldMapperOneColumnMode.AnyCase || column.ColumnMode == FieldMapperOneColumnMode.OnlyInsert))
					// Tento column nemá nastaven režim AnyCase nebo OnlyInsert => přeskočím jej, nemá se dávat do INSERT:
					continue;

				string add1 = column.ColumnName;
				string add2 = column.SqlValue;
				bool wrapLine = ((len1 + addComma.Length + add1.Length > maxLen) || (len2 + addComma.Length + add2.Length > maxLen));
				if (wrapLine)
				{	// Řádek by byl moc dlouhý: vložíme [čárku], CrLf, mezery:
					sql1 += addComma + newLine + spac;
					sql2 += addComma + newLine + spac;
					len1 = spac.Length;
					len2 = spac.Length;
				}
				else
				{	// Řádek nebude tak dlouhý: přidáme jen [čárku]:
					sql1 += addComma;
					sql2 += addComma;
					len1 += addComma.Length;
					len2 += addComma.Length;
				}
				sql1 += add1;
				sql2 += add2;
				len1 += add1.Length;
				len2 += add2.Length;
				if (addComma.Length == 0) addComma = ", ";
			}
			string sql = sql1 + ")" + newLine +
				sql2 + ");" + newLine;

			// MASTER tabulka: musíme vrátit @@IDENTITY:
			if (!withIdentityColumn)
				sql += "SELECT (cast(@@IDENTITY as int)) as new_record_number;" + newLine;

			return sql;
		}
        /// <summary>
        /// Vrací select, který ověří existenci záznamu. Je možno použít před UPDATE.
        /// Vrácená hodnota se má rovnat číslu záznamu. Select má tvar SELECT cislo_subjektu FROM lcs.subjekty WHERE cislo_subjektu = Xxx, kde Xxx je this.RecordNumber
        /// </summary>
        /// <returns></returns>
        internal string GetCommandExists(int recordNumber)
        {
            return "SELECT " + this.IdentityColumnName + " FROM " + this.TableName + " WHERE " + this.IdentityColumnName + " = " + SqlFormat.ToSql(recordNumber);
        }
		#endregion
	}
	#endregion
	#region CLASS FieldMapperOneColumnCls : data jednoho db columnu
	/// <summary>
	/// Třída, které v sobě nese data pro ukládání do jednoho sloupce
	/// </summary>
	internal class FieldMapperOneColumnCls
	{
		internal FieldMapperOneColumnCls(FieldMapperOneColumnMode columnMode, string columnName, object value, int maxLength)
		{
			_ColumnMode = columnMode;
			_ColumnName = columnName;
			_Value = value;
			_MaxLength = maxLength;
		}
		/// <summary> { get; }
		/// Režim tohoto sloupce
		/// </summary>
		internal FieldMapperOneColumnMode ColumnMode { get { return _ColumnMode; } }
		private FieldMapperOneColumnMode _ColumnMode;
		/// <summary> { get; }
		/// Název sloupce
		/// </summary>
		internal string ColumnName { get { return _ColumnName; } }
		private string _ColumnName;
		/// <summary> { get; }
		/// Hodnota do tohoto sloupce
		/// </summary>
		internal object Value { get { return _Value; } }
		private object _Value;
		/// <summary> { get; }
		/// Maximální přípustná délka sloupce odvozeného ze Stringu, nula azáporné = bez omezení
		/// </summary>
		internal int MaxLength { get { return _MaxLength; } }
		private int _MaxLength;
		/// <summary>
		/// Vizualizace
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return "{Column " + ColumnName + " = " + Convert.ToString(Value) + " (" + ColumnMode.ToString() + ")}";
		}
		/// <summary>
		/// Aktuální SQL hodnota.
		/// Je zformátovaná (SqlFormat.ToSql()).
		/// Namísto null je vrácen text NULL.
		/// Pokud je jako Value obsažena hodnota typu String, a je zadaná kladná délka this.MaxLength, pak je string oříznutý ("Vstupní dlouhý text" se zde pro MaxLength = 12 prezentuje jako "N'Vstupní dlou'")
		/// </summary>
		internal string SqlValue
		{
			get
			{
				object value = this.Value;
				if (value == null) return "NULL";
				if (value is System.Data.SqlTypes.INullable && ((System.Data.SqlTypes.INullable)value).IsNull) return "NULL";
				if (value is String && this.MaxLength > 0)
				{	// Value není null, a je String:
					string text = (string)value;
					if (text.Length > this.MaxLength)
						text = text.Substring(0, this.MaxLength);
					return SqlFormat.ToSql(text);
				}
				// Standardní formátování:
				return SqlFormat.ToSql(value);
			}
		}
	}
	/// <summary>
	/// Enum, určuje situaci, kdy se data mají ukládat
	/// </summary>
	internal enum FieldMapperOneColumnMode
	{
		/// <summary>Data tohoto sloupce se mají ukládat jak v INSERT tak v UPDATE příkazu</summary>
		AnyCase,
		/// <summary>Data tohoto sloupce se mají ukládat pouze v příkazu INSERT</summary>
		OnlyInsert,
		/// <summary>Data tohoto sloupce se mají ukládat pouze v příkazu UPDATE</summary>
		OnlyUpdate
	}
	#endregion
	#endregion
    #region INTERFACE IDbRecord, IDbFill
    /// <summary>
	/// Interface IDbRecord : kterákoli třída může implementací tohoto interface výrazně urychlit načítání svých dat z databáze.
	/// Načítání může probíhat buď obecně přes reflection (cca 1 field za mikrosekundu)
	/// anebo přes typovou metodu IDbFill.FillFromReader (cca 8 field za mikrosekundu).
	/// Interface dále předepisuje vlastnost int RecordNumber, která má na záznamu vracet jeho klíč, kterým se záznam zatřídí do Dictionary.
	/// </summary>
    public interface IDbRecord : IDbFill
	{
		/// <summary> { get; set; }
		/// Číslo tohoto záznamu pro jeho ukládání do Dictionary(int).
		/// </summary>
		int RecordNumber { get; set; }
		/// <summary>
		/// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
		/// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
		/// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
		/// Po naplnění mapy se vrací true.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool PrepareSaveData(FieldMapperSave map);
	}
    /// <summary>
    /// Interface IDbFill : kterákoli třída může implementací tohoto interface výrazně urychlit načítání svých dat z databáze.
    /// Načítání může probíhat buď obecně přes reflection (cca 1 field za mikrosekundu)
    /// anebo přes typovou metodu IDbFill.FillFromReader (cca 8 field za mikrosekundu).
    /// </summary>
    public interface IDbFill
    {
        /// <summary>
        /// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
        /// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
        /// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="map"></param>
        /// <returns></returns>
        bool FillFromReader(SqlDataReader reader, FieldMapperLoad map);
    }
    #endregion
	#region TESTY
	/// <summary>
	/// Testy DbLayeru
	/// </summary>
	public class DbLayerTest : Noris.Schedule.Support.CommonTestBase
	{
		#region Test správnosti načítání dat DbLayer Generic == IDbRecord
		/// <summary>
		/// Test správnosti načítání dat DbLayer Generic == IDbRecord
		/// </summary>
		/// <returns></returns>
		[TestPoint("Test správnosti načítání dat DbLayer Generic == IDbRecord", TestScopeType.Standard)]
		public static void DbLayerDataTest()
		{
			string sql = "select * from lcs.product_order_costs where cislo_nonsubjektu between 1 and 1000 order by cislo_nonsubjektu";

			List<ProdOrderCostsGeneric> listPoc1 = Db_Layer.GetList<ProdOrderCostsGeneric>(sql);
			List<ProdOrderCostsIDbRecord> listPoc2 = Db_Layer.GetList<ProdOrderCostsIDbRecord>(sql);

			Assert.IsEqual(listPoc1.Count, listPoc2.Count, "Chyba: jeden select vrátil dva různé počty vět (%A, %B) pro dvě techniky.");
			for (int r = 0; r < listPoc1.Count; r++)
			{
				ProdOrderCostsGeneric pocG = listPoc1[r];
				ProdOrderCostsIDbRecord pocE = listPoc2[r];
				Assert.IsEqual(pocG._cislo_nonsubjektu, pocE._cislo_nonsubjektu, "Rozdíl v datech <cislo_nonsubjektu>: %A != %B.");
				Assert.IsEqual(pocG._date_acq, pocE._date_acq, "Rozdíl v datech <_date_acq>: %A != %B.");
				Assert.IsEqual(pocG._date_event, pocE._date_event, "Rozdíl v datech <_date_event>: %A != %B.");
				Assert.IsEqual(pocG._assignation_ready, pocE._assignation_ready, "Rozdíl v datech <_assignation_ready>: %A != %B.");
				Assert.IsEqual(pocG._cost_kind, pocE._cost_kind, "Rozdíl v datech <_cost_kind>: %A != %B.");
				Assert.IsEqual(pocG._change_type, pocE._change_type, "Rozdíl v datech <_change_type>: %A != %B.");
				Assert.IsEqual(pocG._price1, pocE._price1, "Rozdíl v datech <price1>: %A != %B.");
				Assert.IsEqual(pocG._price2, pocE._price2, "Rozdíl v datech <price2>: %A != %B.");
				Assert.IsEqual(pocG._price3, pocE._price3, "Rozdíl v datech <price3>: %A != %B.");
				Assert.IsEqual(pocG._price4, pocE._price4, "Rozdíl v datech <price4>: %A != %B.");
				Assert.IsEqual(pocG._price5, pocE._price5, "Rozdíl v datech <price5>: %A != %B.");
				Assert.IsEqual(pocG._price6, pocE._price6, "Rozdíl v datech <price6>: %A != %B.");
				Assert.IsEqual(pocG._price7, pocE._price7, "Rozdíl v datech <price7>: %A != %B.");
				Assert.IsEqual(pocG._price8, pocE._price8, "Rozdíl v datech <price8>: %A != %B.");
				Assert.IsEqual(pocG._price9, pocE._price9, "Rozdíl v datech <price9>: %A != %B.");
				Assert.IsEqual(pocG._price10, pocE._price10, "Rozdíl v datech <price10>: %A != %B.");
				Assert.IsEqual(pocG._price11, pocE._price11, "Rozdíl v datech <price11>: %A != %B.");
				Assert.IsEqual(pocG._price12, pocE._price12, "Rozdíl v datech <price12>: %A != %B.");
				Assert.IsEqual(pocG._in_production, pocE._in_production, "Rozdíl v datech <_in_production>: %A != %B.");
				Assert.IsEqual(pocG._parent_object, pocE._parent_object, "Rozdíl v datech <_parent_object>: %A != %B.");
				Assert.IsEqual(pocG._product_order, pocE._product_order, "Rozdíl v datech <_product_order>: %A != %B.");
				Assert.IsEqual(pocG._product_order_structure, pocE._product_order_structure, "Rozdíl v datech <_product_order_structure>: %A != %B.");
				Assert.IsEqual(pocG._product_order_operation, pocE._product_order_operation, "Rozdíl v datech <_product_order_operation>: %A != %B.");
				Assert.IsEqual(pocG._other_costs_po, pocE._other_costs_po, "Rozdíl v datech <_other_costs_po>: %A != %B.");
				Assert.IsEqual(pocG._parent_subject, pocE._parent_subject, "Rozdíl v datech <_parent_subject>: %A != %B.");
				Assert.IsEqual(pocG._operation_report, pocE._operation_report, "Rozdíl v datech <_operation_report>: %A != %B.");
				Assert.IsEqual(pocG._assignation_author, pocE._assignation_author, "Rozdíl v datech <_assignation_author>: %A != %B.");
				Assert.IsEqual(pocG._descendent_ass_doc, pocE._descendent_ass_doc, "Rozdíl v datech <_descendent_ass_doc>: %A != %B.");
				Assert.IsEqual(pocG._descendent_cum_doc, pocE._descendent_cum_doc, "Rozdíl v datech <_descendent_cum_doc>: %A != %B.");
				Assert.IsEqual(pocG._depart, pocE._depart, "Rozdíl v datech <_depart>: %A != %B.");
				Assert.IsEqual(pocG._cost_depart, pocE._cost_depart, "Rozdíl v datech <_cost_depart>: %A != %B.");
				Assert.IsEqual(pocG._activity_range, pocE._activity_range, "Rozdíl v datech <_activity_range>: %A != %B.");
				Assert.IsEqual(pocG._cost_range, pocE._cost_range, "Rozdíl v datech <_cost_range>: %A != %B.");
				Assert.IsEqual(pocG._order_relation, pocE._order_relation, "Rozdíl v datech <_order_relation>: %A != %B.");
				Assert.IsEqual(pocG._activity, pocE._activity, "Rozdíl v datech <_activity>: %A != %B.");
				Assert.IsEqual(pocG._qty_real, pocE._qty_real, "Rozdíl v datech <_qty_real>: %A != %B.");
				Assert.IsEqual(pocG._qty_reject, pocE._qty_reject, "Rozdíl v datech <_qty_reject>: %A != %B.");
				Assert.IsEqual(pocG._measurement_unit, pocE._measurement_unit, "Rozdíl v datech <_measurement_unit>: %A != %B.");
				Assert.IsEqual(pocG._pricing, pocE._pricing, "Rozdíl v datech <_pricing>: %A != %B.");
				Assert.IsEqual(pocG._status, pocE._status, "Rozdíl v datech <_status>: %A != %B.");
				Assert.IsEqual(pocG._reject, pocE._reject, "Rozdíl v datech <_reject>: %A != %B.");
				Assert.IsEqual(pocG._specific_price, pocE._specific_price, "Rozdíl v datech <_specific_price>: %A != %B.");
				Assert.IsEqual(pocG._kod_tuz_mena, pocE._kod_tuz_mena, "Rozdíl v datech <_kod_tuz_mena>: %A != %B.");
			}

		}
		#endregion
		#region Test rychlosti načítání dat generických a dat IDbRecord
		/// <summary>
		/// Test rychlosti načítání dat generických a dat IDbRecord
		/// </summary>
		/// <returns></returns>
		[TestPoint("Test rychlosti načítání dat generických a dat IDbRecord", TestScopeType.TimeOptimize)]
		public static string DbLayerTimeTest()
		{
			string result = "";
			float timeGen;
			
			StopWatchStart();
			List<ProdOrderCostsGeneric> listPoc1 = Db_Layer.GetList<ProdOrderCostsGeneric>("SELECT top 10000 * FROM lcs.product_order_costs");
			timeGen = StopWatchStop();
			result += "Načtení " + listPoc1.Count.ToString() + " položek genericky = " + timeGen.ToString() + " milisekund.\r\n";

			StopWatchStart();
			List<ProdOrderCostsIDbRecord> listPoc2 = Db_Layer.GetList<ProdOrderCostsIDbRecord>("SELECT top 10000 * FROM lcs.product_order_costs");
			timeGen = StopWatchStop();
			result += "Načtení " + listPoc2.Count.ToString() + " položek IDbRecord = " + timeGen.ToString() + " milisekund.\r\n";

			return result;
		}
		#endregion
		#region Test Load, Update, Reset, Save nonsubjektových dat pomocí DbLayer IDbRecord
		/// <summary>
		/// Test Load, Update, Reset, Save nonsubjektových dat pomocí DbLayer IDbRecord
		/// </summary>
		/// <returns></returns>
		[TestPoint("Test Load, Update, Reset, Save nonsubjektových dat pomocí DbLayer IDbRecord", TestScopeType.Standard)]
		public static void DbLayerReadSaveNonsTest()
		{
			try
			{
				DataConnect.TransactionBegin();
				List<int> pocList = Db_Layer.GetList<int>("SELECT cislo_nonsubjektu FROM lcs.product_order_costs WHERE cislo_nonsubjektu between 1 and 1000 ORDER BY cislo_nonsubjektu");

				int recNo = pocList[0];
				ProdOrderCostsIDbRecord recordO = ProdOrderCostsIDbRecord.LoadFromDb(recNo);
				SqlInt32 oldDesc = recordO._descendent_ass_doc;
				SqlInt32 newDesc = (SqlInt32)(oldDesc.IsNull ? 1 : oldDesc.Value + 1);
				recordO._descendent_ass_doc = newDesc;
				Db_Layer.SaveRecord(recordO);

				ProdOrderCostsIDbRecord recordU = ProdOrderCostsIDbRecord.LoadFromDb(recNo);
				Assert.IsEqual(newDesc, recordU._descendent_ass_doc, "Chyba: do záznamu %0 se neuložila / nenačetla hodnota %A, v databázi zůstala hodnota %B.", recNo);

				ProdOrderCostsIDbRecord recordN = new ProdOrderCostsIDbRecord();
				recordN._date_acq = new DateTime(2010, 03, 30, 12, 30, 00);
				recordN._date_event = new DateTime(2010, 03, 30, 12, 30, 00);
				recordN._cost_kind = "Z";
				recordN._change_type = "K";
				recordN._price1 = 12345.67M;
				recordN._specific_price = "N";
				recordN._depart = 1;
				recordN._status = "N";
				Db_Layer.SaveRecord(recordN);
				recNo = recordN._cislo_nonsubjektu;

				ProdOrderCostsIDbRecord recordC = ProdOrderCostsIDbRecord.LoadFromDb(recNo);
				Assert.IsEqual(recordN._price1, recordC._price1, "Chyba: do nového záznamu %0 se neuložila / nenačetla hodnota %A, v databázi zůstala hodnota %B.", recNo);

				// Nedávám:
				// DataConnect.TransactionSetComplete();
				//  = neuloží se updatovaná / insertovaná data!
			}
			finally
			{
				// Rollback:
				DataConnect.TransactionEnd();
			}
		}
		#region SUBCLASSES _ProdOrderCosts* pro testy načítání výrobních pohybů Generic a IDbRecord
		/// <summary>
		/// Testovací třída
		/// </summary>
		protected class ProdOrderCostsGeneric
		{
#pragma warning disable 1591
			internal int _cislo_nonsubjektu;
			internal DateTime _date_acq;
			internal DateTime _date_event;
			internal string _assignation_ready;
			internal string _cost_kind;
			internal string _change_type;
			internal decimal _price1;
			internal decimal _price2;
			internal decimal _price3;
			internal decimal _price4;
			internal decimal _price5;
			internal decimal _price6;
			internal decimal _price7;
			internal decimal _price8;
			internal decimal _price9;
			internal decimal _price10;
			internal decimal _price11;
			internal decimal _price12;
			internal string _in_production;
			internal SqlInt32 _parent_object;
			internal SqlInt32 _product_order;
			internal SqlInt32 _product_order_structure;
			internal SqlInt32 _product_order_operation;
			internal SqlInt32 _other_costs_po;
			internal SqlInt32 _parent_subject;
			internal SqlInt32 _operation_report;
			internal SqlInt32 _assignation_author;
			internal SqlInt32 _descendent_ass_doc;
			internal SqlInt32 _descendent_cum_doc;
			internal SqlInt32 _depart;
			internal SqlInt32 _cost_depart;
			internal SqlInt32 _activity_range;
			internal SqlInt32 _cost_range;
			internal SqlInt32 _order_relation;
			internal SqlInt32 _activity;
			internal decimal _qty_real;
			internal decimal _qty_reject;
			internal SqlInt32 _measurement_unit;
			internal SqlInt32 _pricing;
			internal string _status;
			internal SqlInt32 _reject;
			internal string _specific_price;
			internal string _kod_tuz_mena;
#pragma warning restore 1591
		}
		/// <summary>
		/// Testovací třída
		/// </summary>
		protected class ProdOrderCostsIDbRecord : IDbRecord
		{
			#region _variables
#pragma warning disable 1591
			internal int _cislo_nonsubjektu;
			internal DateTime _date_acq;
			internal DateTime _date_event;
			internal string _assignation_ready;
			internal string _cost_kind;
			internal string _change_type;
			internal decimal _price1;
			internal decimal _price2;
			internal decimal _price3;
			internal decimal _price4;
			internal decimal _price5;
			internal decimal _price6;
			internal decimal _price7;
			internal decimal _price8;
			internal decimal _price9;
			internal decimal _price10;
			internal decimal _price11;
			internal decimal _price12;
			internal decimal _price1_ind;
			internal decimal _price2_ind;
			internal decimal _price3_ind;
			internal decimal _price4_ind;
			internal decimal _price5_ind;
			internal decimal _price6_ind;
			internal decimal _price7_ind;
			internal decimal _price8_ind;
			internal decimal _price9_ind;
			internal decimal _price10_ind;
			internal decimal _price11_ind;
			internal decimal _price12_ind;
			internal string _in_production;
			internal SqlInt32 _parent_object;
			internal SqlInt32 _product_order;
			internal SqlInt32 _product_order_structure;
			internal SqlInt32 _product_order_operation;
			internal SqlInt32 _other_costs_po;
			internal SqlInt32 _parent_subject;
			internal SqlInt32 _operation_report;
			internal SqlInt32 _assignation_author;
			internal SqlInt32 _descendent_ass_doc;
			internal SqlInt32 _descendent_cum_doc;
			internal SqlInt32 _depart;
			internal SqlInt32 _cost_depart;
			internal SqlInt32 _activity_range;
			internal SqlInt32 _cost_range;
			internal SqlInt32 _order_relation;
			internal SqlInt32 _activity;
			internal decimal _qty_real;
			internal decimal _qty_reject;
			internal SqlInt32 _measurement_unit;
			internal SqlInt32 _pricing;
			internal string _status;
			internal SqlInt32 _reject;
			internal string _specific_price;
			internal string _kod_tuz_mena;
#pragma warning restore 1591
			#endregion
			#region IDbRecord Members
			bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
			{
				_cislo_nonsubjektu = (int)map.FillDataIntoField<Int32>("cislo_nonsubjektu", reader);
				_date_acq = (DateTime)map.FillDataIntoField<DateTime>("date_acq", reader);
				_date_event = (DateTime)map.FillDataIntoField<DateTime>("date_event", reader);
				_assignation_ready = (string)map.FillDataIntoField<string>("assignation_ready", reader);
				_cost_kind = (string)map.FillDataIntoField<string>("cost_kind", reader);
				_change_type = (string)map.FillDataIntoField<string>("change_type", reader);
				_price1 = (decimal)map.FillDataIntoField<decimal>("price1", reader);
				_price2 = (decimal)map.FillDataIntoField<decimal>("price2", reader);
				_price3 = (decimal)map.FillDataIntoField<decimal>("price3", reader);
				_price4 = (decimal)map.FillDataIntoField<decimal>("price4", reader);
				_price5 = (decimal)map.FillDataIntoField<decimal>("price5", reader);
				_price6 = (decimal)map.FillDataIntoField<decimal>("price6", reader);
				_price7 = (decimal)map.FillDataIntoField<decimal>("price7", reader);
				_price8 = (decimal)map.FillDataIntoField<decimal>("price8", reader);
				_price9 = (decimal)map.FillDataIntoField<decimal>("price9", reader);
				_price10 = (decimal)map.FillDataIntoField<decimal>("price10", reader);
				_price11 = (decimal)map.FillDataIntoField<decimal>("price11", reader);
				_price12 = (decimal)map.FillDataIntoField<decimal>("price12", reader);
				_price1_ind = (decimal)map.FillDataIntoField<decimal>("price1_ind", reader);
				_price2_ind = (decimal)map.FillDataIntoField<decimal>("price2_ind", reader);
				_price3_ind = (decimal)map.FillDataIntoField<decimal>("price3_ind", reader);
				_price4_ind = (decimal)map.FillDataIntoField<decimal>("price4_ind", reader);
				_price5_ind = (decimal)map.FillDataIntoField<decimal>("price5_ind", reader);
				_price6_ind = (decimal)map.FillDataIntoField<decimal>("price6_ind", reader);
				_price7_ind = (decimal)map.FillDataIntoField<decimal>("price7_ind", reader);
				_price8_ind = (decimal)map.FillDataIntoField<decimal>("price8_ind", reader);
				_price9_ind = (decimal)map.FillDataIntoField<decimal>("price9_ind", reader);
				_price10_ind = (decimal)map.FillDataIntoField<decimal>("price10_ind", reader);
				_price11_ind = (decimal)map.FillDataIntoField<decimal>("price11_ind", reader);
				_price12_ind = (decimal)map.FillDataIntoField<decimal>("price12_ind", reader);
				_in_production = (string)map.FillDataIntoField<string>("in_production", reader);
				_parent_object = (SqlInt32)map.FillDataIntoField<SqlInt32>("parent_object", reader);
				_product_order = (SqlInt32)map.FillDataIntoField<SqlInt32>("product_order", reader);
				_product_order_structure = (SqlInt32)map.FillDataIntoField<SqlInt32>("product_order_structure", reader);
				_product_order_operation = (SqlInt32)map.FillDataIntoField<SqlInt32>("product_order_operation", reader);
				_other_costs_po = (SqlInt32)map.FillDataIntoField<SqlInt32>("other_costs_po", reader);
				_parent_subject = (SqlInt32)map.FillDataIntoField<SqlInt32>("parent_subject", reader);
				_operation_report = (SqlInt32)map.FillDataIntoField<SqlInt32>("operation_report", reader);
				_assignation_author = (SqlInt32)map.FillDataIntoField<SqlInt32>("assignation_author", reader);
				_descendent_ass_doc = (SqlInt32)map.FillDataIntoField<SqlInt32>("descendent_ass_doc", reader);
				_descendent_cum_doc = (SqlInt32)map.FillDataIntoField<SqlInt32>("descendent_cum_doc", reader);
				_depart = (SqlInt32)map.FillDataIntoField<SqlInt32>("depart", reader);
				_cost_depart = (SqlInt32)map.FillDataIntoField<SqlInt32>("cost_depart", reader);
				_activity_range = (SqlInt32)map.FillDataIntoField<SqlInt32>("activity_range", reader);
				_cost_range = (SqlInt32)map.FillDataIntoField<SqlInt32>("cost_range", reader);
				_order_relation = (SqlInt32)map.FillDataIntoField<SqlInt32>("order_relation", reader);
				_activity = (SqlInt32)map.FillDataIntoField<SqlInt32>("activity", reader);
				_qty_real = (decimal)map.FillDataIntoField<decimal>("qty_real", reader);
				_qty_reject = (decimal)map.FillDataIntoField<decimal>("qty_reject", reader);
				_measurement_unit = (SqlInt32)map.FillDataIntoField<SqlInt32>("measurement_unit", reader);
				_pricing = (SqlInt32)map.FillDataIntoField<SqlInt32>("pricing", reader);
				_status = (string)map.FillDataIntoField<string>("status", reader);
				_reject = (SqlInt32)map.FillDataIntoField<SqlInt32>("reject", reader);
				_specific_price = (string)map.FillDataIntoField<string>("specific_price", reader);
				_kod_tuz_mena = (string)map.FillDataIntoField<string>("kod_tuz_mena", reader);
				return true;
			}
			/// <summary>
			/// Číslo záznamu pro účely DbLayer
			/// </summary>
			int IDbRecord.RecordNumber
			{
				get { return _cislo_nonsubjektu; }
				set { _cislo_nonsubjektu = value; }
			}
			/// <summary>
			/// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
			/// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
			/// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
			/// Po naplnění mapy se vrací true.
			/// </summary>
			/// <param name="map"></param>
			/// <returns></returns>
			public virtual bool PrepareSaveData(FieldMapperSave map)
			{
				map.AddTable("lcs.product_order_costs", "cislo_nonsubjektu");
				map.AddColumn("date_acq", _date_acq);
				map.AddColumn("date_event", _date_event);
				map.AddColumn("assignation_ready", _assignation_ready);
				map.AddColumn("cost_kind", _cost_kind);
				map.AddColumn("change_type", _change_type);
				map.AddColumn("price1", _price1);
				map.AddColumn("price2", _price2);
				map.AddColumn("price3", _price3);
				map.AddColumn("price4", _price4);
				map.AddColumn("price5", _price5);
				map.AddColumn("price6", _price6);
				map.AddColumn("price7", _price7);
				map.AddColumn("price8", _price8);
				map.AddColumn("price9", _price9);
				map.AddColumn("price10", _price10);
				map.AddColumn("price11", _price11);
				map.AddColumn("price12", _price12);
				map.AddColumn("price1_ind", _price1_ind);
				map.AddColumn("price2_ind", _price2_ind);
				map.AddColumn("price3_ind", _price3_ind);
				map.AddColumn("price4_ind", _price4_ind);
				map.AddColumn("price5_ind", _price5_ind);
				map.AddColumn("price6_ind", _price6_ind);
				map.AddColumn("price7_ind", _price7_ind);
				map.AddColumn("price8_ind", _price8_ind);
				map.AddColumn("price9_ind", _price9_ind);
				map.AddColumn("price10_ind", _price10_ind);
				map.AddColumn("price11_ind", _price11_ind);
				map.AddColumn("price12_ind", _price12_ind);
				map.AddColumn("in_production", _in_production);
				map.AddColumn("parent_object", _parent_object);
				map.AddColumn("product_order", _product_order);
				map.AddColumn("product_order_structure", _product_order_structure);
				map.AddColumn("product_order_operation", _product_order_operation);
				map.AddColumn("other_costs_po", _other_costs_po);
				map.AddColumn("parent_subject", _parent_subject);
				map.AddColumn("operation_report", _operation_report);
				map.AddColumn("assignation_author", _assignation_author);
				map.AddColumn("descendent_ass_doc", _descendent_ass_doc);
				map.AddColumn("descendent_cum_doc", _descendent_cum_doc);
				map.AddColumn("depart", _depart);
				map.AddColumn("cost_depart", _cost_depart);
				map.AddColumn("activity_range", _activity_range);
				map.AddColumn("cost_range", _cost_range);
				map.AddColumn("order_relation", _order_relation);
				map.AddColumn("activity", _activity);
				map.AddColumn("qty_real", _qty_real);
				map.AddColumn("qty_reject", _qty_reject);
				map.AddColumn("measurement_unit", _measurement_unit);
				map.AddColumn("pricing", _pricing);
				map.AddColumn("status", _status);
				map.AddColumn("reject", _reject);
				map.AddColumn("specific_price", _specific_price);
				map.AddColumn("kod_tuz_mena", _kod_tuz_mena);

				return true;
			}
			#endregion
			#region STATIC GENERÁTORY SELECTU
			/// <summary>
			/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
			/// </summary>
			public static string SqlSelect { get { return "SELECT * FROM lcs.product_order_costs"; } }
			/// <summary>
			/// Jméno sloupce, který obsahuje klíč záznamu, určeno pro filtry.
			/// </summary>
			public static string SqlRecord { get { return "cislo_nonsubjektu"; } }
			#endregion

			internal static ProdOrderCostsIDbRecord LoadFromDb(int recordNumber)
			{
				string sql = ProdOrderCostsIDbRecord.SqlSelect + " WHERE " + ProdOrderCostsIDbRecord.SqlRecord + " = " + recordNumber;
				ProdOrderCostsIDbRecord record = Db_Layer.GetRecord<ProdOrderCostsIDbRecord>(sql);
				return record;
			}
		}
		#endregion
		#endregion
		#region Test Load, Update, Reset, Save subjektových dat pomocí DbLayer IDbRecord
		/// <summary>
		/// Test Load, Update, Reset, Save subjektových dat pomocí DbLayer IDbRecord
		/// </summary>
		/// <returns></returns>
		[TestPoint("Test Load, Update, Reset, Save subjektových dat pomocí DbLayer IDbRecord", TestScopeType.Standard)]
		public static void DbLayerReadSaveSubjTest()
		{
			try
			{
				DataConnect.TransactionBegin();

				// Třída AtestCls, která do datové tabulky kopíruje systémové atributy:
				AtestCls atest1 = new AtestCls();
				atest1.Reference = "00001";
				atest1.Nazev = "Zkušební záznam Atest";
				atest1.FolderNumber = 12345;
				atest1.Obdobi = 2010;
				atest1.DatumOd = new SqlDateTime(2010, 1, 15, 12, 30, 00);
				atest1.DatumDo = new SqlDateTime(2010, 1, 15, 12, 45, 00);
				atest1.Zdroj = 321;
				atest1.Poznamka = "Poznámka k atestu zde nebude.";
				atest1.Save();
				int key1 = atest1.RecordNumber;

				AtestCls atest2 = new AtestCls();
				atest2.Load(key1);
				atest2.Poznamka += "\r\nAnebo sem tu poznámku dáme?";
				atest2.Save();

				AtestCls atest3 = new AtestCls();
				atest3.Load(key1);
				string pozn = atest3.Poznamka;


				// Třída CinnostCls, která do datové tabulky NEPŘENÁŠÍ systémové atributy:
				CinnostCls cinns1 = new CinnostCls();
				cinns1.Reference = "00002";
				cinns1.Nazev = "Zkušební záznam Činnost";
				cinns1.FolderNumber = 12346;
				cinns1.Stupen = "A";
				cinns1.PopisCinnosti = "Úspora energií v míře vyšší než významné.";
				cinns1.Save();
				int key2 = cinns1.RecordNumber;

				CinnostCls cinns2 = new CinnostCls();
				cinns2.Load(key2);

				// Nedávám:
				// DataConnect.TransactionSetComplete();
				//  = neuloží se updatovaná / insertovaná data!
			}
			finally
			{
				// Rollback:
				DataConnect.TransactionEnd();
			}
		}
		#region CLASS AtestCls : Třída odvozená z tabulky lcs.atest - kopíruje do sebe systémové atributy, nemusí se načítat, musí se ukládat
		/// <summary>
		/// AtestCls : Data z Master tabulky třídy 606: Atest (uo_atest_inst), Subjektová
		/// Data načtena z tabulky lcs.atest
		/// </summary>
		protected class AtestCls : RecordCls, Noris.Schedule.Support.Sql.IDbRecord
		{
			#region KONSTRUKCE A PUBLIC OVERRIDE PROPERTY
			/// <summary>
			/// Implicitní konstruktor, zajistí číslování záznamů do jednotné Temporary řady
			/// </summary>
			public AtestCls()
				: base()
			{ }
			/// <summary>
			/// Explicitní konstruktor, dovolí zvolit, zda se pro tento záznam bude generovat Temporary ID
			/// </summary>
			/// <param name="createTemporaryId">true pokud se pro záznam má vytvořit Temporary ID.
			/// Default (false) = nevytvoří se, bude mít RecordNumber = 0.</param>
			public AtestCls(bool createTemporaryId)
				: base(createTemporaryId)
			{ }
			/// <summary>
			/// Číslo třídy: 606
			/// </summary>
			public override int ClassNumber { get { return ClassNr; } }
			/// <summary>Číslo třídy</summary>
			public const int ClassNr = 606;
			/// <summary>Číslo záznamu = cislo_subjektu</summary>
			public override int RecordNumber { get { return base._cislo_subjektu; } }
			/// <summary>IDbRecord.RecordNumber : musí konkrétně implementovat set, protože DbLayer po uložení nového záznamu (kde RecordNumber == 0) do něj vloží přidělený klíč</summary>
			int IDbRecord.RecordNumber
			{
				get { return this.RecordNumber; }
				set { base._cislo_subjektu = value; }
			}
			#endregion
			#region PUBLIC DATA PROPERTY
			/// <summary>Reference</summary>
			public new string Reference { get { return _reference_subjektu; } set { _reference_subjektu = value; } }
			/// <summary>Název</summary>
			public new string Nazev { get { return _nazev_subjektu; } set { _nazev_subjektu = value; } }
			/// <summary>Pořadač</summary>
			public new int FolderNumber { get { return _cislo_poradace; } set { _cislo_poradace = value; } }
			///<summary><para>Db: lcs.atest.obdobi (int null)</para></summary>
			public SqlInt64 Obdobi { get { return _obdobi; } set { _obdobi = value; } }
			///<summary><para>Vztah 5161: Zboží (zprava: Atest)</para><para>Db: lcs.atest.zdroj (int not null)</para></summary>
			public SqlInt32 Zdroj { get { return _zdroj; } set { _zdroj = value; } }
			///<summary><para>Atribut: Datum od</para><para>Db: lcs.atest.datum_od (datetime null)</para></summary>
			public SqlDateTime DatumOd { get { return _datum_od; } set { _datum_od = value; } }
			///<summary><para>Atribut: Datum do</para><para>Db: lcs.atest.datum_do (datetime null)</para></summary>
			public SqlDateTime DatumDo { get { return _datum_do; } set { _datum_do = value; } }
			///<summary><para>Atribut: Poznámka</para><para>Db: lcs.atest.poznamka (varchar (255) null)</para></summary>
			public string Poznamka { get { return _poznamka; } set { _poznamka = value; } }
			#endregion
			#region PROTECTED DATA FIELDS
			#pragma warning disable 1591
			protected SqlInt64 _obdobi;
			protected SqlInt32 _zdroj;
			protected SqlDateTime _datum_od;
			protected SqlDateTime _datum_do;
			protected string _poznamka;
			#pragma warning restore 1591
			#endregion
			#region FILL FROM READER
			/// <summary>
			/// Virtuální metoda, která umožňuje potomkům provádět typovou a rychlou konverzi dat proudících z databáze přes DataReader 
			/// přímo do objektu této třídy, bez použití generické metody FieldInfo.SetValue (která je poněkud pomalá).
			/// Tato metoda v této třídě tedy má naplnit každou svoji instanční proměnnou (field) hodnotou z předaného SqlDataReaderu.
			/// Pro snadné načtení dat je předán objekt mapper, který nabízí svou generickou metodu FillDataIntoField«int»(string dbColumnName, SqlDataReader reader).
			/// Tato metoda vrátí načtená data (typovaná jako objekt).
			/// Čtení touto metodou je cca 6x rychlejší než čtení generickou metodou.
			/// Metoda má vracet true, pokud převzala všechna data. 
			/// Je nanejvýše účelné, aby tak provedla, protože pokud vrátí false, pak se po jejím skončení provede generické ukládání dat (což je 6x pomalejší).
			/// </summary>
			/// <param name='reader'>Vstupní DataReader</param>
			/// <param name='map'>Mapování dat z readeru na fields tohoto objektu</param>
			/// <returns>true = data byla převzata / false = data nepřevzata</returns>
			public override bool FillFromReader(SqlDataReader reader, FieldMapperLoad map)
			{
				base.FillFromReader(reader, map);
				_obdobi = (SqlInt64)map.FillDataIntoField<SqlInt64>("obdobi", reader);
				_zdroj = (SqlInt32)map.FillDataIntoField<SqlInt32>("zdroj", reader);
				_datum_od = (SqlDateTime)map.FillDataIntoField<SqlDateTime>("datum_od", reader);
				_datum_do = (SqlDateTime)map.FillDataIntoField<SqlDateTime>("datum_do", reader);
				_poznamka = (string)map.FillDataIntoField<string>("poznamka", reader);
				return true;
			}
			#endregion
			#region SAVE RECORD
			/// <summary>
			/// Zajistí přípravu svých dat do podkladové vrstvy pro uložení do databáze.
			/// Subjektové třídy musí nejprve volat SubjectCls.PrepareSaveData(this, map);, 
			/// tím se uloží data do tabulky subjektů (a pro nové záznamy se vygeneruje číslo subjektu).
			/// Nonsubjektové třídy to volat nesmí.
			/// </summary>
			/// <param name="map"></param>
			/// <returns></returns>
			public override bool PrepareSaveData(FieldMapperSave map)
			{
				SubjectCls.PrepareSaveData(this, map);                 // Uloží data do lcs.subjekty, tabulku zavře
				SubjectCls.PrepareSaveData(this, map, "lcs.atest");    // Uloží data do lcs.atest, a tabulku nezavírá
				map.AddColumn("obdobi", this.Obdobi);
				map.AddColumn("zdroj", this.Zdroj);
				map.AddColumn("datum_od", this.DatumOd);
				map.AddColumn("datum_do", this.DatumDo);
				map.AddColumn("poznamka", this.Poznamka);
				map.AddTableEnd();
				return true;
			}
			#endregion
			#region STATIC GENERÁTORY SELECTU
			/// <summary>
			/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
			/// </summary>
			public static new string SqlSelect { get { return "SELECT * FROM lcs.atest"; } }
			/// <summary>
			/// Jméno sloupce, který obsahuje klíč záznamu, určeno pro filtry.
			/// </summary>
			public static new string SqlRecord { get { return "cislo_subjektu"; } }
			/// <summary>
			/// Generátor SELECTU pro načítání do CACHE.
			/// Vrátí SQL SELECT, který používá SysCache pro automatické načítání záznamů do cache.
			/// Vrácený select má tvar "SELECT * FROM tabulka [join lcs.subjekty] WHERE [master_tabulka.]key_column", cache si doplní číslo[a] záznamů sama.
			/// </summary>
			/// <returns>Vrátí SQL SELECT, který používá SysCache pro automatické načítání záznamů do cache.</returns>
			public override string GetCacheSelect()
			{
				return SqlSelect + " WHERE " + SqlRecord;
			}
			#endregion
		}
		#endregion
		#region CLASS CinnostCls : Třída odvozená z tabulky lcs.cinnost - nekopíruje do sebe systémové atributy, musí se načítat i ukládat
		/// <summary>
		/// CinnostCls : Data z Master tabulky třídy 427: Činnost (NrsInstance), Subjektová
		/// Data načtena z tabulky lcs.cinnost
		/// </summary>
		protected class CinnostCls : RecordCls, Noris.Schedule.Support.Sql.IDbRecord
		{
			#region KONSTRUKCE A PUBLIC OVERRIDE PROPERTY
			/// <summary>
			/// Implicitní konstruktor, zajistí číslování záznamů do jednotné Temporary řady
			/// </summary>
			public CinnostCls()
				: base()
			{ }
			/// <summary>
			/// Explicitní konstruktor, dovolí zvolit, zda se pro tento záznam bude generovat Temporary ID
			/// </summary>
			/// <param name="createTemporaryId">true pokud se pro záznam má vytvořit Temporary ID.
			/// Default (false) = nevytvoří se, bude mít RecordNumber = 0.</param>
			public CinnostCls(bool createTemporaryId)
				: base(createTemporaryId)
			{ }
			/// <summary>
			/// Číslo třídy: 427
			/// </summary>
			public override int ClassNumber { get { return ClassNr; } }
			/// <summary>Číslo třídy</summary>
			public const int ClassNr = 427;
			/// <summary>Číslo záznamu = cislo_subjektu</summary>
			public override int RecordNumber { get { return base._cislo_subjektu; } }
			/// <summary>IDbRecord.RecordNumber : musí konkrétně implementovat set, protože DbLayer po uložení nového záznamu (kde RecordNumber == 0) do něj vloží přidělený klíč</summary>
			int IDbRecord.RecordNumber
			{
				get { return this.RecordNumber; }
				set { base._cislo_subjektu = value; }
			}
			#endregion
			#region PUBLIC DATA PROPERTY
			///<summary><para>Systémový atribut: reference subjektu</para><para>Db: lcs.subjekty.reference_subjektu (varchar (30) null)</para></summary>
			public new string Reference { get { return _reference_subjektu; } set { _reference_subjektu = value; } }
			///<summary><para>Systémový atribut: název subjektu</para><para>Db: lcs.subjekty.nazev_subjektu (varchar (40) null)</para></summary>
			public new string Nazev { get { return _nazev_subjektu; } set { _nazev_subjektu = value; } }
			///<summary><para>Systémový atribut: číslo pořadače subjektu</para><para>Db: lcs.subjekty.cislo_poradace (int not null)</para></summary>
			public new int FolderNumber { get { return _cislo_poradace; } set { _cislo_poradace = value; } }
			///<summary><para>Atribut: Popis činnosti</para><para>Db: lcs.cinnost.popis_cinnosti (varchar (255) null)</para></summary>
			public string PopisCinnosti { get { return _popis_cinnosti; } set { _popis_cinnosti = value; } }
			///<summary><para>Atribut: Stupeň [valuace_atributu]</para><para>Db: lcs.cinnost.stupen (char (1) null)</para></summary>
			public string Stupen { get { return _stupen; } set { _stupen = value; } }
			#endregion
			#region PROTECTED DATA FIELDS
			#pragma warning disable 1591
			protected string _popis_cinnosti;
			protected string _stupen;
			#pragma warning restore 1591
			#endregion
			#region FILL FROM READER
			/// <summary>
			/// Virtuální metoda, která umožňuje potomkům provádět typovou a rychlou konverzi dat proudících z databáze přes DataReader 
			/// přímo do objektu této třídy, bez použití generické metody FieldInfo.SetValue (která je poněkud pomalá).
			/// Tato metoda v této třídě tedy má naplnit každou svoji instanční proměnnou (field) hodnotou z předaného SqlDataReaderu.
			/// Pro snadné načtení dat je předán objekt mapper, který nabízí svou generickou metodu FillDataIntoField«int»(string dbColumnName, SqlDataReader reader).
			/// Tato metoda vrátí načtená data (typovaná jako objekt).
			/// Čtení touto metodou je cca 6x rychlejší než čtení generickou metodou.
			/// Metoda má vracet true, pokud převzala všechna data. 
			/// Je nanejvýše účelné, aby tak provedla, protože pokud vrátí false, pak se po jejím skončení provede generické ukládání dat (což je 6x pomalejší).
			/// </summary>
			/// <param name='reader'>Vstupní DataReader</param>
			/// <param name='map'>Mapování dat z readeru na fields tohoto objektu</param>
			/// <returns>true = data byla převzata / false = data nepřevzata</returns>
			public override bool FillFromReader(SqlDataReader reader, FieldMapperLoad map)
			{
				base.FillFromReader(reader, map);
				_popis_cinnosti = (string)map.FillDataIntoField<string>("popis_cinnosti", reader);
				_stupen = (string)map.FillDataIntoField<string>("stupen", reader);
				return true;
			}
			#endregion
			#region SAVE RECORD
			/// <summary>
			/// Zajistí přípravu svých dat do podkladové vrstvy pro uložení do databáze.
			/// Subjektové třídy musí nejprve volat SubjectCls.PrepareSaveData(this, map);, 
			/// tím se uloží data do tabulky subjektů (a pro nové záznamy se vygeneruje číslo subjektu).
			/// Nonsubjektové třídy to volat nesmí.
			/// 
			/// </summary>
			/// <param name="map"></param>
			/// <returns></returns>
			public override bool PrepareSaveData(FieldMapperSave map)
			{
				SubjectCls.PrepareSaveData(this, map);                 // Uloží data do lcs.subjekty, tabulku zavře
				map.AddTable("lcs.cinnost", "cislo_subjektu");         // Další sloupce budou ukládány do této tabulky (subjektové sloupce se nekopírují)
				map.AddColumn("popis_cinnosti", this.PopisCinnosti);
				map.AddColumn("stupen", this.Stupen);
				map.AddTableEnd();
				return true;
			}
			#endregion
			#region STATIC GENERÁTORY SELECTU
			/// <summary>
			/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
			/// </summary>
			public static new string SqlSelect { get { return "SELECT * FROM lcs.cinnost join lcs.subjekty on lcs.subjekty.cislo_subjektu = lcs.cinnost.cislo_subjektu"; } }
			/// <summary>
			/// Jméno sloupce, který obsahuje klíč záznamu, určeno pro filtry.
			/// </summary>
			public static new string SqlRecord { get { return "lcs.cinnost.cislo_subjektu"; } }
			/// <summary>
			/// Generátor SELECTU pro načítání do CACHE.
			/// Vrátí SQL SELECT, který používá SysCache pro automatické načítání záznamů do cache.
			/// Vrácený select má tvar "SELECT * FROM tabulka [join lcs.subjekty] WHERE [master_tabulka.]key_column", cache si doplní číslo[a] záznamů sama.
			/// </summary>
			/// <returns>Vrátí SQL SELECT, který používá SysCache pro automatické načítání záznamů do cache.</returns>
			public override string GetCacheSelect()
			{
				return SqlSelect + " WHERE " + SqlRecord;
			}
			#endregion
		}
		#endregion
		#endregion
		#region Test Db_Layer.OpenInputStream()
		/// <summary>
		/// Test, zda funguje metoda Db_Layer.OpenInputStream()
		/// </summary>
		/// <returns></returns>
		[TestPoint("Test Db_Layer.OpenInputStream()", TestScopeType.Enhanced)]
		public static string TestRecStreaming()
		{
			System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();

			_TestSummary summary = new _TestSummary();

			Assert.Section = "LoadDictionary PUS";
			sw.Reset();
			sw.Start();
			Db_Layer.OpenInputStream<_PlanUnitSCls>("SELECT * from lcs.plan_unit_s", _TestRecStreamingOneRec, summary);
			sw.Stop();
			double time1 = 1000D * (double)sw.ElapsedTicks / (double)System.Diagnostics.Stopwatch.Frequency;

			sw.Reset();
			sw.Start();
			List<decimal> summ = Db_Layer.GetList<decimal>("SELECT sum(qty) as sum_qty from lcs.plan_unit_s");
			sw.Stop();
			double time2 = 1000D * (double)sw.ElapsedTicks / (double)System.Diagnostics.Stopwatch.Frequency;
			int itmCnt = summ.Count;
			decimal sumQty = (itmCnt == 1 ? summ[0] : -1M);
			Assert.IsEqual(itmCnt, 1, "Chyba: SELECT sum(qty) měl vrátit 1 záznam, vrátil jich %0.", itmCnt);
			Assert.IsEqual(summary.Qty, sumQty, "Chyba: SELECT sum(qty) vrátil jiný součet, než zaregistrovala metoda (SUM = %0, součet ze záznamů = %1).", sumQty, summary.Qty);

			return
				"Načteno " + summary.Count.ToString() + " záznamů PUS, sumárně " + summary.Qty.ToString() + " kusů zásob, v čase " + time1.ToString() + " ms.\r\n" +
				"Kontrola (SELECT SUM(qty)): součet = " + sumQty.ToString() + " kusů zásob, v čase " + time2.ToString() + " ms.";
		}
		/// <summary>
		/// RecordHandler
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private static void _TestRecStreamingOneRec(object sender, Db_Layer.LoadInputStreamEventArgs<_PlanUnitSCls> e)
		{
			_TestSummary summary = (_TestSummary)e.UserData;
			summary.Count++;
			summary.Qty += e.Record.Qty;
		}
		private class _TestSummary
		{
			public int Count;
			public decimal Qty;
		}
		#endregion
		#region CLASS PlanUnitSCls : Třída odvozená z tabulky lcs.plan_unit_s
		/// <summary>
		/// PlanUnitSCls : Data z Master tabulky třídy 1160: Plánovací jednotka S zdrojů (PlanUnitSInst), Subjektová
		/// Data načtena z tabulky lcs.plan_unit_s
		/// </summary>
		private class _PlanUnitSCls : RecordCls, Noris.Schedule.Support.Sql.IDbRecord
		{
			#region KONSTRUKCE A PUBLIC OVERRIDE PROPERTY
			/// <summary>
			/// Implicitní konstruktor, zajistí číslování záznamů do jednotné Temporary řady
			/// </summary>
			public _PlanUnitSCls()
				: base()
			{ }
			/// <summary>
			/// Explicitní konstruktor, dovolí zvolit, zda se pro tento záznam bude generovat Temporary ID
			/// </summary>
			/// <param name="createTemporaryId">true pokud se pro záznam má vytvořit Temporary ID.
			/// Default (false) = nevytvoří se, bude mít RecordNumber = 0.</param>
			public _PlanUnitSCls(bool createTemporaryId)
				: base(createTemporaryId)
			{ }
			/// <summary>
			/// Číslo třídy: 1160
			/// </summary>
			public override int ClassNumber { get { return ClassNr; } }
			/// <summary>Číslo třídy</summary>
			public const int ClassNr = 1160;
			/// <summary>Číslo záznamu = cislo_subjektu</summary>
			public override int RecordNumber { get { return base._cislo_subjektu; } }
			/// <summary>IDbRecord.RecordNumber : musí konkrétně implementovat set, protože DbLayer po uložení nového záznamu (kde RecordNumber == 0) do něj vloží přidělený klíč</summary>
			int IDbRecord.RecordNumber
			{
				get { return this.RecordNumber; }
				set { base._cislo_subjektu = value; }
			}
			#endregion
			#region PUBLIC DATA PROPERTY
			///<summary><para>Vztah 8616: Zdroj (zprava: Plánovací jednotka)</para><para>Db: lcs.plan_unit_s.source (int not null)</para></summary>
			public int Source { get { return _source; } set { _source = value; } }
			///<summary><para>Vztah 8617: Varianta (zprava: Plánovací jednotka)</para><para>Db: lcs.plan_unit_s.variation (int null)</para></summary>
			public SqlInt32 Variation { get { return _variation; } set { _variation = value; } }
			///<summary><para>Vztah 8619: Zakázka (zprava: Plánovací jednotka)</para><para>Db: lcs.plan_unit_s.order_relation (int null)</para></summary>
			public SqlInt32 OrderRelation { get { return _order_relation; } set { _order_relation = value; } }
			///<summary><para>Atribut: Datum přepočtu [Datum_cas]</para><para>Db: lcs.plan_unit_s.plan_date (smalldatetime not null)</para></summary>
			public DateTime PlanDate { get { return _plan_date; } set { _plan_date = value; } }
			///<summary><para>Atribut: Max. úroveň rozpadu (LLC) [editgeneral]</para><para>Db: lcs.plan_unit_s.llc (int not null)</para></summary>
			public int Llc { get { return _llc; } set { _llc = value; } }
			///<summary><para>Atribut: Počet [editmaskmena]</para><para>Db: lcs.plan_unit_s.qty (numeric_19_6 not null)</para></summary>
			public decimal Qty { get { return _qty; } set { _qty = value; } }
			///<summary><para>Atribut: Počet disponibilní [editmaskmena]</para><para>Db: lcs.plan_unit_s.qty_disp (numeric_19_6 not null)</para></summary>
			public decimal QtyDisp { get { return _qty_disp; } set { _qty_disp = value; } }
			///<summary><para>Atribut: Počet konečný [editmaskmena]</para><para>Db: lcs.plan_unit_s.qty_final (numeric_19_6 not null)</para></summary>
			public decimal QtyFinal { get { return _qty_final; } set { _qty_final = value; } }
			///<summary><para>Atribut: Počet konečný disp [editmaskmena]</para><para>Db: lcs.plan_unit_s.qty_final_disp (numeric_19_6 not null)</para></summary>
			public decimal QtyFinalDisp { get { return _qty_final_disp; } set { _qty_final_disp = value; } }
			///<summary><para>Atribut: Počet objednáno [editmaskmena]</para><para>Db: lcs.plan_unit_s.qty_ord (numeric_19_6 not null)</para></summary>
			public decimal QtyOrd { get { return _qty_ord; } set { _qty_ord = value; } }
			///<summary><para>Atribut: Počet objednáno ve výrobě [editmaskmena]</para><para>Db: lcs.plan_unit_s.qty_ord_in_prod (numeric_19_6 not null)</para></summary>
			public decimal QtyOrdInProd { get { return _qty_ord_in_prod; } set { _qty_ord_in_prod = value; } }
			///<summary><para>Atribut: Počet objednáno výrobou [editmaskmena]</para><para>Db: lcs.plan_unit_s.qty_ord_fr_prod (numeric_19_6 not null)</para></summary>
			public decimal QtyOrdFrProd { get { return _qty_ord_fr_prod; } set { _qty_ord_fr_prod = value; } }
			///<summary><para>Atribut: Počet poptáváno [editmaskmena]</para><para>Db: lcs.plan_unit_s.qty_dem (numeric_19_6 not null)</para></summary>
			public decimal QtyDem { get { return _qty_dem; } set { _qty_dem = value; } }
			///<summary><para>Atribut: Počet potvrzeně objednáno [editmaskmena]</para><para>Db: lcs.plan_unit_s.qty_ord_conf (numeric_19_6 not null)</para></summary>
			public decimal QtyOrdConf { get { return _qty_ord_conf; } set { _qty_ord_conf = value; } }
			///<summary><para>Atribut: Počet rezervováno [editmaskmena]</para><para>Db: lcs.plan_unit_s.qty_res (numeric_19_6 not null)</para></summary>
			public decimal QtyRes { get { return _qty_res; } set { _qty_res = value; } }
			///<summary><para>Atribut: Klíčová pro plánování [typ_ano_ne]</para><para>Db: lcs.plan_unit_s.key_source (char (1) not null)</para></summary>
			public string KeySource { get { return _key_source; } set { _key_source = value; } }
			///<summary><para>Atribut: Datum nápočtu LLC [Datum_cas]</para><para>Db: lcs.plan_unit_s.date_llc (datetime not null)</para></summary>
			public DateTime DateLlc { get { return _date_llc; } set { _date_llc = value; } }
			///<summary><para>Atribut: Počet navrženo příjem [editmaskmena]</para><para>Db: lcs.plan_unit_s.qty_prop_in (numeric_19_6 not null)</para></summary>
			public decimal QtyPropIn { get { return _qty_prop_in; } set { _qty_prop_in = value; } }
			#endregion
			#region PROTECTED DATA FIELDS
			#pragma warning disable 1591
			protected int _source;
			protected SqlInt32 _variation;
			protected SqlInt32 _order_relation;
			protected DateTime _plan_date;
			protected int _llc;
			protected decimal _qty;
			protected decimal _qty_disp;
			protected decimal _qty_final;
			protected decimal _qty_final_disp;
			protected decimal _qty_ord;
			protected decimal _qty_ord_in_prod;
			protected decimal _qty_ord_fr_prod;
			protected decimal _qty_dem;
			protected decimal _qty_ord_conf;
			protected decimal _qty_res;
			protected string _key_source;
			protected DateTime _date_llc;
			protected decimal _qty_prop_in;
			#pragma warning restore 1591
			#endregion
			#region FILL FROM READER
			/// <summary>
			/// Virtuální metoda, která umožňuje potomkům provádět typovou a rychlou konverzi dat proudících z databáze přes DataReader 
			/// přímo do objektu této třídy, bez použití generické metody FieldInfo.SetValue (která je poněkud pomalá).
			/// Tato metoda v této třídě tedy má naplnit každou svoji instanční proměnnou (field) hodnotou z předaného SqlDataReaderu.
			/// Pro snadné načtení dat je předán objekt mapper, který nabízí svou generickou metodu FillDataIntoField«int»(string dbColumnName, SqlDataReader reader).
			/// Tato metoda vrátí načtená data (typovaná jako objekt).
			/// Čtení touto metodou je cca 6x rychlejší než čtení generickou metodou.
			/// Metoda má vracet true, pokud převzala všechna data. 
			/// Je nanejvýše účelné, aby tak provedla, protože pokud vrátí false, pak se po jejím skončení provede generické ukládání dat (což je 6x pomalejší).
			/// </summary>
			/// <param name='reader'>Vstupní DataReader</param>
			/// <param name='map'>Mapování dat z readeru na fields tohoto objektu</param>
			/// <returns>true = data byla převzata / false = data nepřevzata</returns>
			public override bool FillFromReader(SqlDataReader reader, FieldMapperLoad map)
			{
				base.FillFromReader(reader, map);                 // naplní systémové atributy, vrací false
				_source = (int)map.FillDataIntoField<int>("source", reader);
				_variation = (SqlInt32)map.FillDataIntoField<SqlInt32>("variation", reader);
				_order_relation = (SqlInt32)map.FillDataIntoField<SqlInt32>("order_relation", reader);
				_plan_date = (DateTime)map.FillDataIntoField<DateTime>("plan_date", reader);
				_llc = (int)map.FillDataIntoField<int>("llc", reader);
				_qty = (decimal)map.FillDataIntoField<decimal>("qty", reader);
				_qty_disp = (decimal)map.FillDataIntoField<decimal>("qty_disp", reader);
				_qty_final = (decimal)map.FillDataIntoField<decimal>("qty_final", reader);
				_qty_final_disp = (decimal)map.FillDataIntoField<decimal>("qty_final_disp", reader);
				_qty_ord = (decimal)map.FillDataIntoField<decimal>("qty_ord", reader);
				_qty_ord_in_prod = (decimal)map.FillDataIntoField<decimal>("qty_ord_in_prod", reader);
				_qty_ord_fr_prod = (decimal)map.FillDataIntoField<decimal>("qty_ord_fr_prod", reader);
				_qty_dem = (decimal)map.FillDataIntoField<decimal>("qty_dem", reader);
				_qty_ord_conf = (decimal)map.FillDataIntoField<decimal>("qty_ord_conf", reader);
				_qty_res = (decimal)map.FillDataIntoField<decimal>("qty_res", reader);
				_key_source = (string)map.FillDataIntoField<string>("key_source", reader);
				_date_llc = (DateTime)map.FillDataIntoField<DateTime>("date_llc", reader);
				_qty_prop_in = (decimal)map.FillDataIntoField<decimal>("qty_prop_in", reader);
				return true;
			}
			#endregion
			#region STATIC GENERÁTORY SELECTU
			/// <summary>
			/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
			/// </summary>
			public static new string SqlSelect { get { return "SELECT * FROM lcs.plan_unit_s"; } }
			/// <summary>
			/// Jméno sloupce, který obsahuje klíč záznamu, určeno pro filtry.
			/// </summary>
			public static new string SqlRecord { get { return "cislo_subjektu"; } }
			/// <summary>
			/// Generátor SELECTU pro načítání do CACHE.
			/// Vrátí SQL SELECT, který používá SysCache pro automatické načítání záznamů do cache.
			/// Vrácený select má tvar "SELECT * FROM tabulka [join lcs.subjekty] WHERE [master_tabulka.]key_column", cache si doplní číslo[a] záznamů sama.
			/// </summary>
			/// <returns>Vrátí SQL SELECT, který používá SysCache pro automatické načítání záznamů do cache.</returns>
			public override string GetCacheSelect()
			{
				return SqlSelect + " WHERE " + SqlRecord;
			}
			#endregion
		}
		#endregion
	}
	#endregion
}
